,
221 | {
222 | for field in fields {
223 | if field.start + field.width != *last {
224 | // Add a filler
225 | let cell = make_cell(document, None, None, *last - field.start - field.width)?;
226 | row.append_child(&cell)?;
227 | }
228 | let cell = make_cell(
229 | document,
230 | get_contents(field).as_deref(),
231 | get_hover_title(field).as_deref(),
232 | field.width,
233 | )?;
234 | row.append_child(&cell)?;
235 | *last = field.start;
236 | }
237 | Ok(())
238 | }
239 |
--------------------------------------------------------------------------------
/aarch64-esr-web/static/google2d2782625f584348.html:
--------------------------------------------------------------------------------
1 | google-site-verification: google2d2782625f584348.html
--------------------------------------------------------------------------------
/aarch64-esr-web/static/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | AArch64 ESR decoder
6 |
7 |
8 |
9 |
10 |
11 | AArch64 register decoder
12 |
17 |
24 |
25 |
26 | Source and command-line version
27 |
28 |
29 |
--------------------------------------------------------------------------------
/aarch64-esr-web/static/midr.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | AArch64 MIDR decoder
6 |
7 |
8 |
9 |
10 |
11 | AArch64 register decoder
12 |
17 |
24 |
25 |
26 | Source and command-line version
27 |
28 |
29 |
--------------------------------------------------------------------------------
/aarch64-esr-web/static/smccc.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Arm SMCCC decoder
6 |
7 |
8 |
9 |
10 |
11 | AArch64 register decoder
12 |
17 |
24 |
25 |
26 | Source and command-line version
27 |
28 |
29 |
--------------------------------------------------------------------------------
/aarch64-esr-web/static/style.css:
--------------------------------------------------------------------------------
1 | table {
2 | border-collapse: collapse;
3 | }
4 | td {
5 | border: 1px solid black;
6 | }
7 | tr.value td {
8 | font-family: monospace;
9 | }
10 | tr.description td:not(:empty) {
11 | background-color: #ffffdd;
12 | }
13 | tr.name td:not(:empty) {
14 | background-color: #ddffdd;
15 | font-family: monospace;
16 | }
17 | p#error {
18 | color: red;
19 | }
20 | ul.tabbar {
21 | margin: 0;
22 | padding-top: 5px;
23 | padding-bottom: 0;
24 | padding-left: 5px;
25 | padding-right: 5px;
26 | width: 100%;
27 | list-style: none;
28 | border-bottom: 1px solid #ddffdd;
29 | }
30 | .tabbar li {
31 | display: inline-block;
32 | }
33 | .tabbar li.current {
34 | background-color: #ddffdd;
35 | padding: 10px;
36 | }
37 | .tabbar li a {
38 | background-color: #ffffdd;
39 | display: block;
40 | padding: 10px;
41 | }
42 | .tabbar li a:hover {
43 | background-color: #cceecc;
44 | }
45 |
--------------------------------------------------------------------------------
/aarch64-esr-web/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const CopyPlugin = require("copy-webpack-plugin");
3 | const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin");
4 |
5 | const dist = path.resolve(__dirname, "dist");
6 |
7 | module.exports = {
8 | mode: "production",
9 | entry: {
10 | index: "./js/index.js",
11 | },
12 | output: {
13 | path: dist,
14 | filename: "[name].js",
15 | },
16 | devtool: "source-map",
17 | optimization: {
18 | minimize: true,
19 | usedExports: true,
20 | },
21 | experiments: {
22 | asyncWebAssembly: true,
23 | },
24 | plugins: [
25 | new CopyPlugin({ patterns: [path.resolve(__dirname, "static")] }),
26 |
27 | new WasmPackPlugin({
28 | crateDirectory: __dirname,
29 | }),
30 | ],
31 | };
32 |
--------------------------------------------------------------------------------
/src/esr/abort.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::{DecodeError, FieldInfo};
16 | use std::fmt::{self, Debug, Display, Formatter};
17 |
18 | /// Decodes the ISS value for an Instruction Abort.
19 | pub fn decode_iss_instruction_abort(iss: u64) -> Result, DecodeError> {
20 | let res0a = FieldInfo::get(iss, "RES0", Some("Reserved"), 13, 25).check_res0()?;
21 | let fnv = FieldInfo::get_bit(iss, "FnV", Some("FAR not Valid"), 10).describe_bit(describe_fnv);
22 | let ea = FieldInfo::get_bit(iss, "EA", Some("External abort type"), 9);
23 | let res0b = FieldInfo::get_bit(iss, "RES0", Some("Reserved"), 8).check_res0()?;
24 | let s1ptw = FieldInfo::get_bit(iss, "S1PTW", Some("Stage-1 translation table walk"), 7);
25 | let res0c = FieldInfo::get_bit(iss, "RES0", Some("Reserved"), 6).check_res0()?;
26 | let ifsc = FieldInfo::get(iss, "IFSC", Some("Instruction Fault Status Code"), 0, 6)
27 | .describe(describe_fsc)?;
28 |
29 | let set = if ifsc.value == 0b010000 {
30 | FieldInfo::get(iss, "SET", Some("Synchronous Error Type"), 11, 13).describe(describe_set)?
31 | } else {
32 | FieldInfo::get(iss, "RES0", Some("Reserved"), 11, 13)
33 | };
34 |
35 | Ok(vec![res0a, set, fnv, ea, res0b, s1ptw, res0c, ifsc])
36 | }
37 |
38 | /// Decodes the ISS value for a Data Abort.
39 | pub fn decode_iss_data_abort(iss: u64) -> Result, DecodeError> {
40 | let isv = FieldInfo::get_bit(iss, "ISV", Some("Instruction Syndrome Valid"), 24)
41 | .describe_bit(describe_isv);
42 |
43 | let intruction_syndrome_fields = if isv.as_bit() {
44 | // These fields are part of the instruction syndrome, and are only valid if ISV is true.
45 | let sas = FieldInfo::get(iss, "SAS", Some("Syndrome Access Size"), 22, 24);
46 | let sas_value = match sas.value {
47 | 0b00 => SyndromeAccessSize::Byte,
48 | 0b01 => SyndromeAccessSize::Halfword,
49 | 0b10 => SyndromeAccessSize::Word,
50 | 0b11 => SyndromeAccessSize::Doubleword,
51 | _ => unreachable!(),
52 | };
53 | let sas = sas.with_description(sas_value.to_string());
54 | let sse = FieldInfo::get_bit(iss, "SSE", Some("Syndrome Sign Extend"), 21);
55 | let srt = FieldInfo::get(iss, "SRT", Some("Syndrome Register Transfer"), 16, 21);
56 | let sf = FieldInfo::get_bit(iss, "SF", Some("Sixty-Four"), 15).describe_bit(describe_sf);
57 | let ar =
58 | FieldInfo::get_bit(iss, "AR", Some("Acquire/Release"), 14).describe_bit(describe_ar);
59 | vec![sas, sse, srt, sf, ar]
60 | } else {
61 | let res0 = FieldInfo::get(iss, "RES0", Some("Reserved"), 14, 24).check_res0()?;
62 | vec![res0]
63 | };
64 |
65 | let vncr = FieldInfo::get_bit(iss, "VNCR", None, 13);
66 | let fnv = FieldInfo::get_bit(iss, "FnV", Some("FAR not Valid"), 10).describe_bit(describe_fnv);
67 | let ea = FieldInfo::get_bit(iss, "EA", Some("External abort type"), 9);
68 | let cm = FieldInfo::get_bit(iss, "CM", Some("Cache Maintenance"), 8);
69 | let s1ptw = FieldInfo::get_bit(iss, "S1PTW", Some("Stage-1 translation table walk"), 7);
70 | let wnr = FieldInfo::get_bit(iss, "WnR", Some("Write not Read"), 6).describe_bit(describe_wnr);
71 | let dfsc =
72 | FieldInfo::get(iss, "DFSC", Some("Data Fault Status Code"), 0, 6).describe(describe_fsc)?;
73 | let set = if dfsc.value == 0b010000 {
74 | FieldInfo::get(iss, "SET", Some("Synchronous Error Type"), 11, 13).describe(describe_set)?
75 | } else {
76 | FieldInfo::get(iss, "RES0", Some("Reserved"), 11, 13)
77 | };
78 |
79 | let mut fields = vec![isv];
80 | fields.extend(intruction_syndrome_fields);
81 | fields.extend(vec![vncr, set, fnv, ea, cm, s1ptw, wnr, dfsc]);
82 | Ok(fields)
83 | }
84 |
85 | #[derive(Copy, Clone, Debug, Eq, PartialEq)]
86 | enum SyndromeAccessSize {
87 | Byte = 0b00,
88 | Halfword = 0b01,
89 | Word = 0b10,
90 | Doubleword = 0b11,
91 | }
92 |
93 | impl Display for SyndromeAccessSize {
94 | fn fmt(&self, f: &mut Formatter) -> fmt::Result {
95 | let s = match self {
96 | Self::Byte => "byte",
97 | Self::Halfword => "halfword",
98 | Self::Word => "word",
99 | Self::Doubleword => "doubleword",
100 | };
101 | write!(f, "{}", s)
102 | }
103 | }
104 |
105 | fn describe_isv(isv: bool) -> &'static str {
106 | if isv {
107 | "Valid instruction syndrome"
108 | } else {
109 | "No valid instruction syndrome"
110 | }
111 | }
112 |
113 | fn describe_sf(sf: bool) -> &'static str {
114 | if sf {
115 | "64-bit wide register"
116 | } else {
117 | "32-bit wide register"
118 | }
119 | }
120 |
121 | fn describe_ar(ar: bool) -> &'static str {
122 | if ar {
123 | "Acquire/release semantics"
124 | } else {
125 | "No acquire/release semantics"
126 | }
127 | }
128 |
129 | fn describe_fnv(fnv: bool) -> &'static str {
130 | if fnv {
131 | "FAR is not valid, it holds an unknown value"
132 | } else {
133 | "FAR is valid"
134 | }
135 | }
136 |
137 | fn describe_wnr(wnr: bool) -> &'static str {
138 | if wnr {
139 | "Abort caused by writing to memory"
140 | } else {
141 | "Abort caused by reading from memory"
142 | }
143 | }
144 |
145 | fn describe_fsc(fsc: u64) -> Result<&'static str, DecodeError> {
146 | let description = match fsc {
147 | 0b000000 => {
148 | "Address size fault, level 0 of translation or translation table base register."
149 | }
150 | 0b000001 => "Address size fault, level 1.",
151 | 0b000010 => "Address size fault, level 2.",
152 | 0b000011 => "Address size fault, level 3.",
153 | 0b000100 => "Translation fault, level 0.",
154 | 0b000101 => "Translation fault, level 1.",
155 | 0b000110 => "Translation fault, level 2.",
156 | 0b000111 => "Translation fault, level 3.",
157 | 0b001001 => "Access flag fault, level 1.",
158 | 0b001010 => "Access flag fault, level 2.",
159 | 0b001011 => "Access flag fault, level 3.",
160 | 0b001000 => "Access flag fault, level 0.",
161 | 0b001100 => "Permission fault, level 0.",
162 | 0b001101 => "Permission fault, level 1.",
163 | 0b001110 => "Permission fault, level 2.",
164 | 0b001111 => "Permission fault, level 3.",
165 | 0b010000 => {
166 | "Synchronous External abort, not on translation table walk or hardware update of \
167 | translation table."
168 | }
169 | 0b010001 => "Synchronous Tag Check Fault.",
170 | 0b010011 => {
171 | "Synchronous External abort on translation table walk or hardware update of \
172 | translation table, level -1."
173 | }
174 | 0b010100 => {
175 | "Synchronous External abort on translation table walk or hardware update of \
176 | translation table, level 0."
177 | }
178 | 0b010101 => {
179 | "Synchronous External abort on translation table walk or hardware update of \
180 | translation table, level 1."
181 | }
182 | 0b010110 => {
183 | "Synchronous External abort on translation table walk or hardware update of \
184 | translation table, level 2."
185 | }
186 | 0b010111 => {
187 | "Synchronous External abort on translation table walk or hardware update of \
188 | translation table, level 3."
189 | }
190 | 0b011000 => {
191 | "Synchronous parity or ECC error on memory access, not on translation table walk."
192 | }
193 | 0b011011 => {
194 | "Synchronous parity or ECC error on memory access on translation table walk or \
195 | hardware update of translation table, level -1."
196 | }
197 | 0b011100 => {
198 | "Synchronous parity or ECC error on memory access on translation table walk or \
199 | hardware update of translation table, level 0."
200 | }
201 | 0b011101 => {
202 | "Synchronous parity or ECC error on memory access on translation table walk or \
203 | hardware update of translation table, level 1."
204 | }
205 | 0b011110 => {
206 | "Synchronous parity or ECC error on memory access on translation table walk or \
207 | hardware update of translation table, level 2."
208 | }
209 | 0b011111 => {
210 | "Synchronous parity or ECC error on memory access on translation table walk or \
211 | hardware update of translation table, level 3."
212 | }
213 | 0b100001 => "Alignment fault.",
214 | 0b100011 => {
215 | "Granule Protection Fault on translation table walk or hardware update of \
216 | translation table, level -1."
217 | }
218 | 0b100100 => {
219 | "Granule Protection Fault on translation table walk or hardware update of \
220 | translation table, level 0."
221 | }
222 | 0b100101 => {
223 | "Granule Protection Fault on translation table walk or hardware update of \
224 | translation table, level 1."
225 | }
226 | 0b100110 => {
227 | "Granule Protection Fault on translation table walk or hardware update of \
228 | translation table, level 2."
229 | }
230 | 0b100111 => {
231 | "Granule Protection Fault on translation table walk or hardware update of \
232 | translation table, level 3."
233 | }
234 | 0b101000 => {
235 | "Granule Protection Fault, not on translation table walk or hardware update of \
236 | translation table."
237 | }
238 | 0b101001 => "Address size fault, level -1.",
239 | 0b101011 => "Translation fault, level -1.",
240 | 0b110000 => "TLB conflict abort.",
241 | 0b110001 => "Unsupported atomic hardware update fault.",
242 | 0b110100 => "IMPLEMENTATION DEFINED fault (Lockdown).",
243 | 0b110101 => "IMPLEMENTATION DEFINED fault (Unsupported Exclusive or Atomic access).",
244 | _ => return Err(DecodeError::InvalidFsc { fsc }),
245 | };
246 | Ok(description)
247 | }
248 |
249 | fn describe_set(set: u64) -> Result<&'static str, DecodeError> {
250 | Ok(match set {
251 | 0b00 => "Recoverable state (UER)",
252 | 0b10 => "Uncontainable (UC)",
253 | 0b11 => "Restartable state (UEO)",
254 | _ => return Err(DecodeError::InvalidSet { set }),
255 | })
256 | }
257 |
--------------------------------------------------------------------------------
/src/esr/breakpoint.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::{DecodeError, FieldInfo};
16 |
17 | /// Decodes the ISS value for a Breakpoint or Vector Catch debug exception.
18 | pub fn decode_iss_breakpoint_vector_catch(iss: u64) -> Result, DecodeError> {
19 | let res0 = FieldInfo::get(iss, "RES0", Some("Reserved"), 6, 25).check_res0()?;
20 | let ifsc = FieldInfo::get(iss, "IFSC", Some("Instruction Fault Status Code"), 0, 6)
21 | .describe(describe_fsc)?;
22 |
23 | Ok(vec![res0, ifsc])
24 | }
25 |
26 | /// Decodes the ISS value for a Software Step exception.
27 | pub fn decode_iss_software_step(iss: u64) -> Result, DecodeError> {
28 | let isv = FieldInfo::get_bit(iss, "ISV", Some("Instruction Syndrome Valid"), 24)
29 | .describe_bit(describe_isv);
30 | let res0 = FieldInfo::get(iss, "RES0", Some("Reserved"), 7, 24).check_res0()?;
31 | let ex = if isv.as_bit() {
32 | FieldInfo::get_bit(iss, "EX", Some("Exclusive operation"), 6).describe_bit(describe_ex)
33 | } else {
34 | FieldInfo::get_bit(iss, "RES0", Some("Reserved because ISV is false"), 6).check_res0()?
35 | };
36 | let ifsc = FieldInfo::get(iss, "IFSC", Some("Instruction Fault Status Code"), 0, 6)
37 | .describe(describe_fsc)?;
38 |
39 | Ok(vec![isv, res0, ex, ifsc])
40 | }
41 |
42 | /// Decodes the ISS value for a Watchpoint exception.
43 | pub fn decode_iss_watchpoint(iss: u64) -> Result, DecodeError> {
44 | let res0a = FieldInfo::get(iss, "RES0", Some("Reserved"), 15, 25).check_res0()?;
45 | let res0b = FieldInfo::get_bit(iss, "RES0", Some("Reserved"), 14).check_res0()?;
46 | let vncr = FieldInfo::get_bit(iss, "VNCR", None, 13);
47 | let res0c = FieldInfo::get(iss, "RES0", Some("Reserved"), 9, 13).check_res0()?;
48 | let cm = FieldInfo::get_bit(iss, "CM", Some("Cache Maintenance"), 8);
49 | let res0d = FieldInfo::get_bit(iss, "RES0", Some("Reserved"), 7).check_res0()?;
50 | let wnr = FieldInfo::get_bit(iss, "WnR", Some("Write not Read"), 6).describe_bit(describe_wnr);
51 | let dfsc =
52 | FieldInfo::get(iss, "DFSC", Some("Data Fault Status Code"), 0, 6).describe(describe_fsc)?;
53 |
54 | Ok(vec![res0a, res0b, vncr, res0c, cm, res0d, wnr, dfsc])
55 | }
56 |
57 | /// Decodes the ISS value for a Breakpoint instruction.
58 | pub fn decode_iss_breakpoint(iss: u64) -> Result, DecodeError> {
59 | let res0 = FieldInfo::get(iss, "RES0", Some("Reserved"), 16, 25).check_res0()?;
60 | let comment = FieldInfo::get(
61 | iss,
62 | "Comment",
63 | Some("Instruction comment field or immediate field"),
64 | 0,
65 | 16,
66 | );
67 |
68 | Ok(vec![res0, comment])
69 | }
70 |
71 | fn describe_fsc(fsc: u64) -> Result<&'static str, DecodeError> {
72 | match fsc {
73 | 0b100010 => Ok("Debug exception"),
74 | _ => Err(DecodeError::InvalidFsc { fsc }),
75 | }
76 | }
77 |
78 | fn describe_isv(isv: bool) -> &'static str {
79 | if isv {
80 | "EX bit is valid"
81 | } else {
82 | "EX bit is RES0"
83 | }
84 | }
85 |
86 | fn describe_ex(ex: bool) -> &'static str {
87 | if ex {
88 | "A Load-Exclusive instruction was stepped"
89 | } else {
90 | "Some instruction other than a Load-Exclusive was stepped"
91 | }
92 | }
93 |
94 | fn describe_wnr(wnr: bool) -> &'static str {
95 | if wnr {
96 | "Watchpoint caused by writing to memory"
97 | } else {
98 | "Watchpoint caused by reading from memory"
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/esr/bti.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::{DecodeError, FieldInfo};
16 |
17 | /// Decodes the ISS value for a Branch Target Exception.
18 | pub fn decode_iss_bti(iss: u64) -> Result, DecodeError> {
19 | let res0 = FieldInfo::get(iss, "RES0", Some("Reserved"), 2, 25).check_res0()?;
20 | let btype = FieldInfo::get(iss, "BTYPE", Some("PSTATE.BTYPE value"), 0, 2);
21 |
22 | Ok(vec![res0, btype])
23 | }
24 |
--------------------------------------------------------------------------------
/src/esr/common.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //! Description functions shared between multiple modules.
16 |
17 | pub fn describe_cv(cv: bool) -> &'static str {
18 | if cv {
19 | "COND is valid"
20 | } else {
21 | "COND is not valid"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/esr/fp.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::{DecodeError, FieldInfo};
16 |
17 | /// Decodes the ISS value for a floating-point exception.
18 | pub fn decode_iss_fp(iss: u64) -> Result, DecodeError> {
19 | let res0a = FieldInfo::get_bit(iss, "RES0", Some("Reserved"), 24).check_res0()?;
20 | let tfv =
21 | FieldInfo::get_bit(iss, "TFV", Some("Trapped Fault Valid"), 23).describe_bit(describe_tfv);
22 | let res0b = FieldInfo::get(iss, "RES0", Some("Reserved"), 11, 23).check_res0()?;
23 | let vecitr = FieldInfo::get(iss, "VECITR", Some("RES1 or UNKNOWN"), 8, 11);
24 | let idf = FieldInfo::get_bit(iss, "IDF", Some("Input Denormal"), 7).describe_bit(describe_idf);
25 | let res0c = FieldInfo::get(iss, "RES0", Some("Reserved"), 5, 7).check_res0()?;
26 | let ixf = FieldInfo::get_bit(iss, "IXF", Some("Inexact"), 4).describe_bit(describe_ixf);
27 | let uff = FieldInfo::get_bit(iss, "UFF", Some("Underflow"), 3).describe_bit(describe_uff);
28 | let off = FieldInfo::get_bit(iss, "OFF", Some("Overflow"), 2).describe_bit(describe_off);
29 | let dzf = FieldInfo::get_bit(iss, "DZF", Some("Divide by Zero"), 1).describe_bit(describe_dzf);
30 | let iof =
31 | FieldInfo::get_bit(iss, "IOF", Some("Invalid Operation"), 0).describe_bit(describe_iof);
32 |
33 | Ok(vec![
34 | res0a, tfv, res0b, vecitr, idf, res0c, ixf, uff, off, dzf, iof,
35 | ])
36 | }
37 |
38 | fn describe_tfv(tfv: bool) -> &'static str {
39 | if tfv {
40 | "One or more floating-point exceptions occurred; IDF, IXF, UFF, OFF, DZF and IOF hold information about what."
41 | } else {
42 | "IDF, IXF, UFF, OFF, DZF and IOF do not hold valid information."
43 | }
44 | }
45 |
46 | fn describe_idf(idf: bool) -> &'static str {
47 | if idf {
48 | "Input denormal floating-point exception occurred."
49 | } else {
50 | "Input denormal floating-point exception did not occur."
51 | }
52 | }
53 |
54 | fn describe_ixf(ixf: bool) -> &'static str {
55 | if ixf {
56 | "Inexact floating-point exception occurred."
57 | } else {
58 | "Inexact floating-point exception did not occur."
59 | }
60 | }
61 |
62 | fn describe_uff(uff: bool) -> &'static str {
63 | if uff {
64 | "Underflow floating-point exception occurred."
65 | } else {
66 | "Underflow floating-point exception did not occur."
67 | }
68 | }
69 |
70 | fn describe_off(off: bool) -> &'static str {
71 | if off {
72 | "Overflow floating-point exception occurred."
73 | } else {
74 | "Overflow floating-point exception did not occur."
75 | }
76 | }
77 |
78 | fn describe_dzf(dzf: bool) -> &'static str {
79 | if dzf {
80 | "Divide by Zero floating-point exception occurred."
81 | } else {
82 | "Divide by Zero floating-point exception did not occur."
83 | }
84 | }
85 |
86 | fn describe_iof(iof: bool) -> &'static str {
87 | if iof {
88 | "Invalid Operation floating-point exception occurred."
89 | } else {
90 | "Invalid Operation floating-point exception did not occur."
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/esr/hvc.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::{DecodeError, FieldInfo};
16 |
17 | /// Decodes the ISS value for an HVC or SVC exception.
18 | pub fn decode_iss_hvc(iss: u64) -> Result, DecodeError> {
19 | let res0 = FieldInfo::get(iss, "RES0", Some("Reserved"), 16, 25).check_res0()?;
20 | let imm16 = FieldInfo::get(iss, "imm16", Some("Value of the immediate field"), 0, 16);
21 |
22 | Ok(vec![res0, imm16])
23 | }
24 |
--------------------------------------------------------------------------------
/src/esr/ld64b.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::{DecodeError, FieldInfo};
16 |
17 | /// Decodes the ISS value for a trapped LD64B or ST64B* instruction.
18 | pub fn decode_iss_ld64b(iss: u64) -> Result, DecodeError> {
19 | let iss = FieldInfo::get(iss, "ISS", None, 0, 25).describe(describe_iss_ld64b)?;
20 | Ok(vec![iss])
21 | }
22 |
23 | fn describe_iss_ld64b(iss: u64) -> Result<&'static str, DecodeError> {
24 | match iss {
25 | 0b00 => Ok("ST64BV trapped"),
26 | 0b01 => Ok("ST64BV0 trapped"),
27 | 0b10 => Ok("LD64B or ST64B trapped"),
28 | _ => Err(DecodeError::InvalidLd64bIss { iss }),
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/esr/ldc.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use super::common::describe_cv;
16 | use crate::{DecodeError, FieldInfo};
17 |
18 | /// Decodes the ISS value for a trapped LDC or STC instruction.
19 | pub fn decode_iss_ldc(iss: u64) -> Result, DecodeError> {
20 | let cv =
21 | FieldInfo::get_bit(iss, "CV", Some("Condition code valid"), 24).describe_bit(describe_cv);
22 | let cond = FieldInfo::get(
23 | iss,
24 | "COND",
25 | Some("Condition code of the trapped instruction"),
26 | 20,
27 | 24,
28 | );
29 | let imm8 = FieldInfo::get(
30 | iss,
31 | "imm8",
32 | Some("Immediate value of the trapped instruction"),
33 | 12,
34 | 20,
35 | );
36 | let res0 = FieldInfo::get(iss, "RES0", Some("Reserved"), 10, 12).check_res0()?;
37 | let rn = FieldInfo::get(
38 | iss,
39 | "Rn",
40 | Some("General-purpose register number of the trapped instruction"),
41 | 5,
42 | 10,
43 | );
44 | let offset = FieldInfo::get_bit(
45 | iss,
46 | "Offset",
47 | Some("Whether the offset is added or subtracted"),
48 | 4,
49 | )
50 | .describe_bit(describe_offset);
51 | let am = FieldInfo::get(iss, "AM", Some("Addressing Mode"), 1, 4).describe(describe_am)?;
52 | let direction = FieldInfo::get_bit(
53 | iss,
54 | "Direction",
55 | Some("Direction of the trapped instruction"),
56 | 0,
57 | )
58 | .describe_bit(describe_direction);
59 |
60 | Ok(vec![cv, cond, imm8, res0, rn, offset, am, direction])
61 | }
62 |
63 | fn describe_offset(offset: bool) -> &'static str {
64 | if offset {
65 | "Add offset"
66 | } else {
67 | "Subtract offset"
68 | }
69 | }
70 |
71 | fn describe_am(am: u64) -> Result<&'static str, DecodeError> {
72 | match am {
73 | 0b000 => Ok("Immediate unindexed"),
74 | 0b001 => Ok("Immediate post-indexed"),
75 | 0b010 => Ok("Immediate offset"),
76 | 0b011 => Ok("Immediate pre-indexed"),
77 | 0b100 => Ok("Reserved for trapped STR or T32 LDC"),
78 | 0b110 => Ok("Reserved for trapped STC"),
79 | _ => Err(DecodeError::InvalidAm { am }),
80 | }
81 | }
82 |
83 | fn describe_direction(direction: bool) -> &'static str {
84 | if direction {
85 | "Read from memory (LDC)"
86 | } else {
87 | "Write to memory (STC)"
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/esr/mcr.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use super::common::describe_cv;
16 | use crate::{DecodeError, FieldInfo};
17 |
18 | /// Decodes the ISS value for an MCR or MRC access.
19 | pub fn decode_iss_mcr(iss: u64) -> Result, DecodeError> {
20 | let cv =
21 | FieldInfo::get_bit(iss, "CV", Some("Condition code valid"), 24).describe_bit(describe_cv);
22 | let cond = FieldInfo::get(
23 | iss,
24 | "COND",
25 | Some("Condition code of the trapped instruction"),
26 | 20,
27 | 24,
28 | );
29 | let opc2 = FieldInfo::get(iss, "Opc2", None, 17, 20);
30 | let opc1 = FieldInfo::get(iss, "Opc1", None, 14, 17);
31 | let crn = FieldInfo::get(iss, "CRn", None, 10, 14);
32 | let rt = FieldInfo::get(iss, "Rt", None, 5, 10);
33 | let crm = FieldInfo::get(iss, "CRm", None, 1, 5);
34 | let direction = FieldInfo::get_bit(
35 | iss,
36 | "Direction",
37 | Some("Direction of the trapped instruction"),
38 | 0,
39 | )
40 | .describe_bit(describe_direction);
41 |
42 | Ok(vec![cv, cond, opc2, opc1, crn, rt, crm, direction])
43 | }
44 |
45 | /// Decodes the ISS value for an MCRR or MRRC access.
46 | pub fn decode_iss_mcrr(iss: u64) -> Result, DecodeError> {
47 | let cv =
48 | FieldInfo::get_bit(iss, "CV", Some("Condition code valid"), 24).describe_bit(describe_cv);
49 | let cond = FieldInfo::get(
50 | iss,
51 | "COND",
52 | Some("Condition code of the trapped instruction"),
53 | 20,
54 | 24,
55 | );
56 | let opc1 = FieldInfo::get(iss, "Opc2", None, 16, 20);
57 | let res0 = FieldInfo::get_bit(iss, "RES0", Some("Reserved"), 15).check_res0()?;
58 | let rt2 = FieldInfo::get(iss, "Rt2", None, 10, 15);
59 | let rt = FieldInfo::get(iss, "Rt", None, 5, 10);
60 | let crm = FieldInfo::get(iss, "CRm", None, 1, 5);
61 | let direction = FieldInfo::get_bit(
62 | iss,
63 | "Direction",
64 | Some("Direction of the trapped instruction"),
65 | 0,
66 | )
67 | .describe_bit(describe_direction);
68 |
69 | Ok(vec![cv, cond, opc1, res0, rt2, rt, crm, direction])
70 | }
71 |
72 | fn describe_direction(direction: bool) -> &'static str {
73 | if direction {
74 | "Read from system register (MRC or VMRS)"
75 | } else {
76 | "Write to system register (MCR)"
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/esr/mod.rs:
--------------------------------------------------------------------------------
1 | mod abort;
2 | mod breakpoint;
3 | mod bti;
4 | mod common;
5 | mod fp;
6 | mod hvc;
7 | mod ld64b;
8 | mod ldc;
9 | mod mcr;
10 | mod msr;
11 | mod pauth;
12 | mod serror;
13 | mod sve;
14 | #[cfg(test)]
15 | mod tests;
16 | mod wf;
17 |
18 | use super::{DecodeError, FieldInfo};
19 | use abort::{decode_iss_data_abort, decode_iss_instruction_abort};
20 | use breakpoint::{
21 | decode_iss_breakpoint, decode_iss_breakpoint_vector_catch, decode_iss_software_step,
22 | decode_iss_watchpoint,
23 | };
24 | use bti::decode_iss_bti;
25 | use fp::decode_iss_fp;
26 | use hvc::decode_iss_hvc;
27 | use ld64b::decode_iss_ld64b;
28 | use ldc::decode_iss_ldc;
29 | use mcr::{decode_iss_mcr, decode_iss_mcrr};
30 | use msr::decode_iss_msr;
31 | use pauth::decode_iss_pauth;
32 | use serror::decode_iss_serror;
33 | use sve::decode_iss_sve;
34 | use wf::decode_iss_wf;
35 |
36 | fn decode_iss_res0(iss: u64) -> Result, DecodeError> {
37 | let res0 = FieldInfo::get(iss, "RES0", Some("Reserved"), 0, 25)
38 | .check_res0()?
39 | .with_description("ISS is RES0".to_string());
40 | Ok(vec![res0])
41 | }
42 |
43 | /// Decodes the given Exception Syndrome Register value, or returns an error if it is not valid.
44 | pub fn decode(esr: u64) -> Result, DecodeError> {
45 | let res0 = FieldInfo::get(esr, "RES0", Some("Reserved"), 37, 64).check_res0()?;
46 | let iss2 = FieldInfo::get(esr, "ISS2", None, 32, 37);
47 | let ec = FieldInfo::get(esr, "EC", Some("Exception Class"), 26, 32);
48 | let il =
49 | FieldInfo::get_bit(esr, "IL", Some("Instruction Length"), 25).describe_bit(describe_il);
50 | let iss = FieldInfo::get(esr, "ISS", Some("Instruction Specific Syndrome"), 0, 25);
51 | let (class, iss_subfields, iss_description) = match ec.value {
52 | 0b000000 => ("Unknown reason", decode_iss_res0(iss.value)?, None),
53 | 0b000001 => (
54 | "Wrapped WF* instruction execution",
55 | decode_iss_wf(iss.value)?,
56 | None,
57 | ),
58 | 0b000011 => (
59 | "Trapped MCR or MRC access with coproc=0b1111",
60 | decode_iss_mcr(iss.value)?,
61 | None,
62 | ),
63 | 0b000100 => (
64 | "Trapped MCRR or MRRC access with coproc=0b1111",
65 | decode_iss_mcrr(iss.value)?,
66 | None,
67 | ),
68 | 0b000101 => (
69 | "Trapped MCR or MRC access with coproc=0b1110",
70 | decode_iss_mcr(iss.value)?,
71 | None,
72 | ),
73 | 0b000110 => (
74 | "Trapped LDC or STC access",
75 | decode_iss_ldc(iss.value)?,
76 | None,
77 | ),
78 | 0b000111 => (
79 | "Trapped access to SVE, Advanced SIMD or floating point",
80 | decode_iss_sve(iss.value)?,
81 | None,
82 | ),
83 | 0b001010 => (
84 | "Trapped execution of an LD64B, ST64B, ST64BV, or ST64BV0 instruction",
85 | decode_iss_ld64b(iss.value)?,
86 | None,
87 | ),
88 | 0b001100 => (
89 | "Trapped MRRC access with (coproc==0b1110)",
90 | decode_iss_mcrr(iss.value)?,
91 | None,
92 | ),
93 | 0b001101 => ("Branch Target Exception", decode_iss_bti(iss.value)?, None),
94 | 0b001110 => ("Illegal Execution state", decode_iss_res0(iss.value)?, None),
95 | 0b010001 => (
96 | "SVC instruction execution in AArch32 state",
97 | decode_iss_hvc(iss.value)?,
98 | None,
99 | ),
100 | 0b010101 => (
101 | "SVC instruction execution in AArch64 state",
102 | decode_iss_hvc(iss.value)?,
103 | None,
104 | ),
105 | 0b010110 => (
106 | "HVC instruction execution in AArch64 state",
107 | decode_iss_hvc(iss.value)?,
108 | None,
109 | ),
110 | 0b010111 => (
111 | "SMC instruction execution in AArch64 state",
112 | decode_iss_hvc(iss.value)?,
113 | None,
114 | ),
115 | 0b011000 => {
116 | let (subfields, description) = decode_iss_msr(iss.value)?;
117 | (
118 | "Trapped MSR, MRS or System instruction execution in AArch64 state",
119 | subfields,
120 | description,
121 | )
122 | }
123 | 0b011001 => (
124 | "Access to SVE functionality trapped as a result of CPACR_EL1.ZEN, CPTR_EL2.ZEN, \
125 | CPTR_EL2.TZ, or CPTR_EL3.EZ",
126 | decode_iss_res0(iss.value)?,
127 | None,
128 | ),
129 | 0b011100 => (
130 | "Exception from a Pointer Authentication instruction authentication failure",
131 | decode_iss_pauth(iss.value)?,
132 | None,
133 | ),
134 | 0b100000 => (
135 | "Instruction Abort from a lower Exception level",
136 | decode_iss_instruction_abort(iss.value)?,
137 | None,
138 | ),
139 | 0b100001 => (
140 | "Instruction Abort taken without a change in Exception level",
141 | decode_iss_instruction_abort(iss.value)?,
142 | None,
143 | ),
144 | 0b100010 => (
145 | "PC alignment fault exception",
146 | decode_iss_res0(iss.value)?,
147 | None,
148 | ),
149 | 0b100100 => (
150 | "Data Abort from a lower Exception level",
151 | decode_iss_data_abort(iss.value)?,
152 | None,
153 | ),
154 | 0b100101 => (
155 | "Data Abort taken without a change in Exception level",
156 | decode_iss_data_abort(iss.value)?,
157 | None,
158 | ),
159 | 0b100110 => (
160 | "SP alignment fault exception",
161 | decode_iss_res0(iss.value)?,
162 | None,
163 | ),
164 | 0b101000 => (
165 | "Trapped floating-point exception taken from AArch32 state",
166 | decode_iss_fp(iss.value)?,
167 | None,
168 | ),
169 | 0b101100 => (
170 | "Trapped floating-point exception taken from AArch64 state",
171 | decode_iss_fp(iss.value)?,
172 | None,
173 | ),
174 | 0b101111 => ("SError interrupt", decode_iss_serror(iss.value)?, None),
175 | 0b110000 => (
176 | "Breakpoint exception from a lower Exception level",
177 | decode_iss_breakpoint_vector_catch(iss.value)?,
178 | None,
179 | ),
180 | 0b110001 => (
181 | "Breakpoint exception taken without a change in Exception level",
182 | decode_iss_breakpoint_vector_catch(iss.value)?,
183 | None,
184 | ),
185 | 0b110010 => (
186 | "Software Step exception from a lower Exception level",
187 | decode_iss_software_step(iss.value)?,
188 | None,
189 | ),
190 | 0b110011 => (
191 | "Software Step exception taken without a change in Exception level",
192 | decode_iss_software_step(iss.value)?,
193 | None,
194 | ),
195 | 0b110100 => (
196 | "Watchpoint exception from a lower Exception level",
197 | decode_iss_watchpoint(iss.value)?,
198 | None,
199 | ),
200 | 0b110101 => (
201 | "Watchpoint exception taken without a change in Exception level",
202 | decode_iss_watchpoint(iss.value)?,
203 | None,
204 | ),
205 | 0b111000 => (
206 | "BKPT instruction execution in AArch32 state",
207 | decode_iss_breakpoint(iss.value)?,
208 | None,
209 | ),
210 | 0b111100 => (
211 | "BRK instruction execution in AArch64 state",
212 | decode_iss_breakpoint(iss.value)?,
213 | None,
214 | ),
215 | _ => return Err(DecodeError::InvalidEc { ec: ec.value }),
216 | };
217 | let iss = FieldInfo {
218 | description: iss_description,
219 | subfields: iss_subfields,
220 | ..iss
221 | };
222 | let ec = ec.with_description(class.to_string());
223 | Ok(vec![res0, iss2, ec, il, iss])
224 | }
225 |
226 | fn describe_il(il: bool) -> &'static str {
227 | if il {
228 | "32-bit instruction trapped"
229 | } else {
230 | "16-bit instruction trapped"
231 | }
232 | }
233 |
--------------------------------------------------------------------------------
/src/esr/msr.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::{DecodeError, FieldInfo};
16 |
17 | /// Decodes the ISS value for an MSR or MRS instruction.
18 | pub fn decode_iss_msr(iss: u64) -> Result<(Vec, Option), DecodeError> {
19 | let res0 = FieldInfo::get(iss, "RES0", Some("Reserved"), 22, 25).check_res0()?;
20 | let op0 = FieldInfo::get(iss, "Op0", None, 20, 22);
21 | let op2 = FieldInfo::get(iss, "Op2", None, 17, 20);
22 | let op1 = FieldInfo::get(iss, "Op1", None, 14, 17);
23 | let crn = FieldInfo::get(iss, "CRn", None, 10, 14);
24 | let rt = FieldInfo::get(
25 | iss,
26 | "Rt",
27 | Some("General-purpose register number of the trapped instruction"),
28 | 5,
29 | 10,
30 | );
31 | let crm = FieldInfo::get(iss, "CRm", None, 1, 5);
32 | let direction = FieldInfo::get_bit(
33 | iss,
34 | "Direction",
35 | Some("Direction of the trapped instruction"),
36 | 0,
37 | )
38 | .describe_bit(describe_direction);
39 |
40 | let name = sysreg_name(op0.value, op1.value, op2.value, crn.value, crm.value);
41 | let description = if direction.value == 0 {
42 | format!("MSR {}, x{}", name, rt.value)
43 | } else {
44 | format!("MRS x{}, {}", rt.value, name)
45 | };
46 |
47 | Ok((
48 | vec![res0, op0, op2, op1, crn, rt, crm, direction],
49 | Some(description),
50 | ))
51 | }
52 |
53 | fn describe_direction(direction: bool) -> &'static str {
54 | if direction {
55 | "Read from system register (MRS)"
56 | } else {
57 | "Write to system register (MSR)"
58 | }
59 | }
60 |
61 | fn sysreg_name(op0: u64, op1: u64, op2: u64, crn: u64, crm: u64) -> &'static str {
62 | match (op0, crn, op1, crm, op2) {
63 | (3, 1, 0, 0, 1) => "ACTLR_EL1",
64 | (3, 1, 4, 0, 1) => "ACTLR_EL2",
65 | (3, 1, 6, 0, 1) => "ACTLR_EL3",
66 | (3, 0, 1, 0, 7) => "AIDR_EL1",
67 | (3, 5, 0, 1, 0) => "AFSR0_EL1",
68 | (3, 5, 4, 1, 0) => "AFSR0_EL2",
69 | (3, 5, 6, 1, 0) => "AFSR0_EL3",
70 | (3, 5, 0, 1, 1) => "AFSR1_EL1",
71 | (3, 5, 4, 1, 1) => "AFSR1_EL2",
72 | (3, 5, 6, 1, 1) => "AFSR1_EL3",
73 | (3, 10, 0, 3, 0) => "AMAIR_EL1",
74 | (3, 10, 4, 3, 0) => "AMAIR_EL2",
75 | (3, 10, 6, 3, 0) => "AMAIR_EL3",
76 | (3, 0, 1, 0, 0) => "CCSIDR_EL1",
77 | (3, 0, 1, 0, 1) => "CLIDR_EL1",
78 | (3, 1, 0, 0, 2) => "CPACR_EL1",
79 | (3, 1, 4, 1, 2) => "CPTR_EL2",
80 | (3, 1, 6, 1, 2) => "CPTR_EL3",
81 | (3, 0, 2, 0, 0) => "CSSELR_EL1",
82 | (3, 0, 3, 0, 1) => "CTR_EL0",
83 | (3, 12, 0, 1, 1) => "DISR_EL1",
84 | (3, 5, 0, 3, 0) => "ERRIDR_EL1",
85 | (3, 5, 0, 3, 1) => "ERRSELR_EL1",
86 | (3, 5, 0, 4, 3) => "ERXADDR_EL1",
87 | (3, 5, 0, 4, 1) => "ERXCTLR_EL1",
88 | (3, 5, 0, 4, 0) => "ERXFR_EL1",
89 | (3, 5, 0, 5, 0) => "ERXMISC0_EL1",
90 | (3, 5, 0, 5, 1) => "ERXMISC1_EL1",
91 | (3, 5, 0, 4, 2) => "ERXSTATUS_EL1",
92 | (3, 5, 0, 2, 0) => "ESR_EL1",
93 | (3, 5, 4, 2, 0) => "ESR_EL2",
94 | (3, 5, 6, 2, 0) => "ESR_EL3",
95 | (3, 1, 4, 1, 7) => "HACR_EL2",
96 | (3, 1, 4, 1, 0) => "HCR_EL2",
97 | (3, 0, 0, 1, 3) => "ID_AFR0_EL1",
98 | (3, 0, 0, 1, 2) => "ID_DFR0_EL1",
99 | (3, 0, 0, 2, 0) => "ID_ISAR0_EL1",
100 | (3, 0, 0, 2, 1) => "ID_ISAR1_EL1",
101 | (3, 0, 0, 2, 2) => "ID_ISAR2_EL1",
102 | (3, 0, 0, 2, 3) => "ID_ISAR3_EL1",
103 | (3, 0, 0, 2, 4) => "ID_ISAR4_EL1",
104 | (3, 0, 0, 2, 5) => "ID_ISAR5_EL1",
105 | (3, 0, 0, 2, 7) => "ID_ISAR6_EL1",
106 | (3, 0, 0, 1, 4) => "ID_MMFR0_EL1",
107 | (3, 0, 0, 1, 5) => "ID_MMFR1_EL1",
108 | (3, 0, 0, 1, 6) => "ID_MMFR2_EL1",
109 | (3, 0, 0, 1, 7) => "ID_MMFR3_EL1",
110 | (3, 0, 0, 2, 6) => "ID_MMFR4_EL1",
111 | (3, 0, 0, 1, 0) => "ID_PFR0_EL1",
112 | (3, 0, 0, 1, 1) => "ID_PFR1_EL1",
113 | (3, 0, 0, 3, 4) => "ID_PFR2_EL1",
114 | (3, 0, 0, 5, 0) => "ID_AA64DFR0_EL1",
115 | (3, 0, 0, 6, 0) => "ID_AA64ISAR0_EL1",
116 | (3, 0, 0, 6, 1) => "ID_AA64ISAR1_EL1",
117 | (3, 0, 0, 7, 0) => "ID_AA64MMFR0_EL1",
118 | (3, 0, 0, 7, 1) => "ID_AA64MMFR1_EL1",
119 | (3, 0, 0, 7, 2) => "ID_AA64MMFR2_EL1",
120 | (3, 0, 0, 4, 0) => "ID_AA64PFR0_EL1",
121 | (3, 5, 4, 0, 1) => "IFSR32_EL2",
122 | (3, 10, 0, 4, 3) => "LORC_EL1",
123 | (3, 10, 0, 4, 7) => "LORID_EL1",
124 | (3, 10, 0, 4, 2) => "LORN_EL1",
125 | (3, 1, 6, 3, 1) => "MDCR_EL3",
126 | (3, 0, 0, 0, 0) => "MIDR_EL1",
127 | (3, 0, 0, 0, 5) => "MPIDR_EL1",
128 | (3, 7, 0, 4, 0) => "PAR_EL1",
129 | (3, 12, 6, 0, 1) => "RVBAR_EL3",
130 | (3, 0, 0, 0, 6) => "REVIDR_EL1",
131 | (3, 1, 0, 0, 0) => "SCTLR_EL1",
132 | (3, 1, 6, 0, 0) => "SCTLR_EL3",
133 | (3, 2, 0, 0, 2) => "TCR_EL1",
134 | (3, 2, 4, 0, 2) => "TCR_EL2",
135 | (3, 2, 6, 0, 2) => "TCR_EL3",
136 | (3, 2, 0, 0, 0) => "TTBR0_EL1",
137 | (3, 2, 4, 0, 0) => "TTBR0_EL2",
138 | (3, 2, 6, 0, 0) => "TTBR0_EL3",
139 | (3, 2, 0, 0, 1) => "TTBR1_EL1",
140 | (3, 2, 4, 0, 1) => "TTBR1_EL2",
141 | (3, 12, 4, 1, 1) => "VDISR_EL2",
142 | (3, 5, 4, 2, 3) => "VSESR_EL2",
143 | (3, 2, 4, 1, 2) => "VTCR_EL2",
144 | (3, 2, 4, 1, 0) => "VTTBR_EL2",
145 | (3, 5, 5, 1, 0) => "AFSR0_EL12",
146 | (3, 5, 5, 1, 1) => "AFSR1_EL12",
147 | (3, 10, 5, 3, 0) => "AMAIR_EL12",
148 | (3, 14, 3, 0, 0) => "CNTFRQ_EL0",
149 | (3, 14, 4, 1, 0) => "CNTHCTL_EL2",
150 | (3, 14, 4, 2, 1) => "CNTHP_CTL_EL2",
151 | (3, 14, 4, 2, 2) => "CNTHP_CVAL_EL2",
152 | (3, 14, 4, 2, 0) => "CNTHP_TVAL_EL2",
153 | (3, 14, 4, 3, 1) => "CNTHV_CTL_EL2",
154 | (3, 14, 4, 3, 2) => "CNTHV_CVAL_EL2",
155 | (3, 14, 4, 3, 0) => "CNTHV_TVAL_EL2",
156 | (3, 14, 0, 1, 0) => "CNTKCTL_EL1",
157 | (3, 14, 5, 1, 0) => "CNTKCTL_EL12",
158 | (3, 14, 3, 2, 1) => "CNTP_CTL_EL0",
159 | (3, 14, 5, 2, 1) => "CNTP_CTL_EL02",
160 | (3, 14, 3, 2, 2) => "CNTP_CVAL_EL0",
161 | (3, 14, 5, 2, 2) => "CNTP_CVAL_EL02",
162 | (3, 14, 3, 2, 0) => "CNTP_TVAL_EL0",
163 | (3, 14, 5, 2, 0) => "CNTP_TVAL_EL02",
164 | (3, 14, 3, 0, 1) => "CNTPCT_EL0",
165 | (3, 14, 7, 2, 1) => "CNTPS_CTL_EL1",
166 | (3, 14, 7, 2, 2) => "CNTPS_CVAL_EL1",
167 | (3, 14, 7, 2, 0) => "CNTPS_TVAL_EL1",
168 | (3, 14, 3, 3, 1) => "CNTV_CTL_EL0",
169 | (3, 14, 5, 3, 1) => "CNTV_CTL_EL02",
170 | (3, 14, 3, 3, 2) => "CNTV_CVAL_EL0",
171 | (3, 14, 5, 3, 2) => "CNTV_CVAL_EL02",
172 | (3, 14, 3, 3, 0) => "CNTV_TVAL_EL0",
173 | (3, 14, 5, 3, 0) => "CNTV_TVAL_EL02",
174 | (3, 14, 3, 0, 2) => "CNTVCT_EL0",
175 | (3, 14, 4, 0, 3) => "CNTVOFF_EL2",
176 | (3, 13, 0, 0, 1) => "CONTEXTIDR_EL1",
177 | (3, 13, 5, 0, 1) => "CONTEXTIDR_EL12",
178 | (3, 13, 4, 0, 1) => "CONTEXTIDR_EL2",
179 | (3, 1, 5, 0, 2) => "CPACR_EL12",
180 | (3, 3, 4, 0, 0) => "DACR32_EL2",
181 | (3, 5, 5, 2, 0) => "ESR_EL12",
182 | (3, 6, 0, 0, 0) => "FAR_EL1",
183 | (3, 6, 5, 0, 0) => "FAR_EL12",
184 | (3, 6, 4, 0, 0) => "FAR_EL2",
185 | (3, 6, 6, 0, 0) => "FAR_EL3",
186 | (3, 5, 4, 3, 0) => "FPEXC32_EL2",
187 | (3, 6, 4, 0, 4) => "HPFAR_EL2",
188 | (3, 1, 4, 1, 3) => "HSTR_EL2",
189 | (3, 0, 0, 5, 4) => "ID_AA64AFR0_EL1",
190 | (3, 0, 0, 5, 5) => "ID_AA64AFR1_EL1",
191 | (3, 0, 0, 5, 1) => "ID_AA64DFR1_EL1",
192 | (3, 0, 0, 4, 1) => "ID_AA64PFR1_EL1",
193 | (3, 12, 0, 1, 0) => "ISR_EL1",
194 | (3, 10, 0, 4, 1) => "LOREA_EL1",
195 | (3, 10, 0, 4, 0) => "LORSA_EL1",
196 | (3, 10, 0, 2, 0) => "MAIR_EL1",
197 | (3, 10, 5, 2, 0) => "MAIR_EL12",
198 | (3, 10, 4, 2, 0) => "MAIR_EL2",
199 | (3, 10, 6, 2, 0) => "MAIR_EL3",
200 | (3, 1, 4, 1, 1) => "MDCR_EL2",
201 | (3, 0, 0, 3, 0) => "MVFR0_EL1",
202 | (3, 0, 0, 3, 1) => "MVFR1_EL1",
203 | (3, 0, 0, 3, 2) => "MVFR2_EL1",
204 | (3, 12, 6, 0, 2) => "RMR_EL3",
205 | (3, 1, 6, 1, 0) => "SCR_EL3",
206 | (3, 1, 5, 0, 0) => "SCTLR_EL12",
207 | (3, 1, 4, 0, 0) => "SCTLR_EL2",
208 | (3, 1, 6, 1, 1) => "SDER32_EL3",
209 | (3, 2, 5, 0, 2) => "TCR_EL12",
210 | (3, 13, 3, 0, 2) => "TPIDR_EL0",
211 | (3, 13, 0, 0, 4) => "TPIDR_EL1",
212 | (3, 13, 4, 0, 2) => "TPIDR_EL2",
213 | (3, 13, 6, 0, 2) => "TPIDR_EL3",
214 | (3, 13, 3, 0, 3) => "TPIDRRO_EL0",
215 | (3, 2, 5, 0, 0) => "TTBR0_EL12",
216 | (3, 2, 5, 0, 1) => "TTBR1_EL12",
217 | (3, 12, 0, 0, 0) => "VBAR_EL1",
218 | (3, 12, 5, 0, 0) => "VBAR_EL12",
219 | (3, 12, 4, 0, 0) => "VBAR_EL2",
220 | (3, 12, 6, 0, 0) => "VBAR_EL3",
221 | (3, 0, 4, 0, 5) => "VMPIDR_EL2",
222 | (3, 0, 4, 0, 0) => "VPIDR_EL2",
223 | _ => "unknown",
224 | }
225 | }
226 |
--------------------------------------------------------------------------------
/src/esr/pauth.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::{DecodeError, FieldInfo};
16 |
17 | /// Decodes the ISS value for a Pointer Authentication failure.
18 | pub fn decode_iss_pauth(iss: u64) -> Result, DecodeError> {
19 | let res0 = FieldInfo::get(iss, "RES0", Some("Reserved"), 2, 25).check_res0()?;
20 | let instruction_or_data =
21 | FieldInfo::get_bit(iss, "IorD", Some("Instruction key or Data key"), 1)
22 | .describe_bit(describe_instruction_or_data);
23 | let a_or_b =
24 | FieldInfo::get_bit(iss, "AorB", Some("A key or B key"), 0).describe_bit(describe_a_or_b);
25 |
26 | Ok(vec![res0, instruction_or_data, a_or_b])
27 | }
28 |
29 | fn describe_instruction_or_data(instruction_or_data: bool) -> &'static str {
30 | if instruction_or_data {
31 | "Data Key"
32 | } else {
33 | "Instruction Key"
34 | }
35 | }
36 |
37 | fn describe_a_or_b(a_or_b: bool) -> &'static str {
38 | if a_or_b {
39 | "B Key"
40 | } else {
41 | "A Key"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/esr/serror.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use crate::{DecodeError, FieldInfo};
16 |
17 | /// Decodes the ISS value for an SError interrupt.
18 | pub fn decode_iss_serror(iss: u64) -> Result, DecodeError> {
19 | let ids = FieldInfo::get_bit(iss, "IDS", Some("Implementation Defined Syndrome"), 24)
20 | .describe_bit(describe_ids);
21 | let platform_fields = if ids.as_bit() {
22 | let impdef = FieldInfo::get(iss, "IMPDEF", Some("Implementation defined"), 0, 24);
23 | vec![impdef]
24 | } else {
25 | let dfsc = FieldInfo::get(iss, "DFSC", Some("Data Fault Status Code"), 0, 6)
26 | .describe(describe_dfsc)?;
27 |
28 | let res0a = FieldInfo::get(iss, "RES0", Some("Reserved"), 14, 24).check_res0()?;
29 | let iesb = if dfsc.value == 0b010001 {
30 | FieldInfo::get_bit(
31 | iss,
32 | "IESB",
33 | Some("Implicit Error Synchronisation event"),
34 | 13,
35 | )
36 | .describe_bit(describe_iesb)
37 | } else {
38 | FieldInfo::get_bit(iss, "RES0", Some("Reserved for this DFSC value"), 13)
39 | .check_res0()?
40 | };
41 | let aet = FieldInfo::get(iss, "AET", Some("Asynchronous Error Type"), 10, 13)
42 | .describe(describe_aet)?;
43 | let ea = FieldInfo::get_bit(iss, "EA", Some("External Abort type"), 9);
44 | let res0b = FieldInfo::get(iss, "RES0", Some("Reserved"), 6, 9).check_res0()?;
45 | vec![res0a, iesb, aet, ea, res0b, dfsc]
46 | };
47 |
48 | let mut fields = vec![ids];
49 | fields.extend(platform_fields);
50 | Ok(fields)
51 | }
52 |
53 | fn describe_ids(ids: bool) -> &'static str {
54 | if ids {
55 | "The rest of the ISS is encoded in an implementation-defined format"
56 | } else {
57 | "The rest of the ISS is encoded according to the platform"
58 | }
59 | }
60 |
61 | fn describe_iesb(iesb: bool) -> &'static str {
62 | if iesb {
63 | "The SError interrupt was synchronized by the implicit error synchronization event and taken immediately."
64 | } else {
65 | "The SError interrupt was not synchronized by the implicit error synchronization event or not taken immediately."
66 | }
67 | }
68 |
69 | fn describe_aet(aet: u64) -> Result<&'static str, DecodeError> {
70 | match aet {
71 | 0b000 => Ok("Uncontainable (UC)"),
72 | 0b001 => Ok("Unrecoverable state (UEU)"),
73 | 0b010 => Ok("Restartable state (UEO)"),
74 | 0b011 => Ok("Recoverable state (UER)"),
75 | 0x110 => Ok("Corrected (CE)"),
76 | _ => Err(DecodeError::InvalidAet { aet }),
77 | }
78 | }
79 |
80 | fn describe_dfsc(dfsc: u64) -> Result<&'static str, DecodeError> {
81 | match dfsc {
82 | 0b000000 => Ok("Uncategorized error"),
83 | 0b010001 => Ok("Asynchronous SError interrupt"),
84 | _ => Err(DecodeError::InvalidFsc { fsc: dfsc }),
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/esr/sve.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use super::common::describe_cv;
16 | use crate::{DecodeError, FieldInfo};
17 |
18 | /// Decodes the ISS value for a trapped SVE, Advanced SIMD or FP instruction.
19 | pub fn decode_iss_sve(iss: u64) -> Result, DecodeError> {
20 | let cv =
21 | FieldInfo::get_bit(iss, "CV", Some("Condition code valid"), 24).describe_bit(describe_cv);
22 | let cond = FieldInfo::get(
23 | iss,
24 | "COND",
25 | Some("Condition code of the trapped instruction"),
26 | 20,
27 | 24,
28 | );
29 | let res0 = FieldInfo::get(iss, "RES0", Some("Reserved"), 0, 20).check_res0()?;
30 |
31 | Ok(vec![cv, cond, res0])
32 | }
33 |
--------------------------------------------------------------------------------
/src/esr/tests.rs:
--------------------------------------------------------------------------------
1 | use super::decode;
2 | use crate::FieldInfo;
3 |
4 | #[test]
5 | fn unknown() {
6 | let decoded = decode(0).unwrap();
7 | assert_eq!(
8 | decoded,
9 | vec![
10 | FieldInfo {
11 | name: "RES0",
12 | long_name: Some("Reserved"),
13 | start: 37,
14 | width: 27,
15 | value: 0,
16 | description: None,
17 | subfields: vec![],
18 | },
19 | FieldInfo {
20 | name: "ISS2",
21 | long_name: None,
22 | start: 32,
23 | width: 5,
24 | value: 0,
25 | description: None,
26 | subfields: vec![],
27 | },
28 | FieldInfo {
29 | name: "EC",
30 | long_name: Some("Exception Class"),
31 | start: 26,
32 | width: 6,
33 | value: 0,
34 | description: Some("Unknown reason".to_string()),
35 | subfields: vec![],
36 | },
37 | FieldInfo {
38 | name: "IL",
39 | long_name: Some("Instruction Length"),
40 | start: 25,
41 | width: 1,
42 | value: 0,
43 | description: Some("16-bit instruction trapped".to_string()),
44 | subfields: vec![],
45 | },
46 | FieldInfo {
47 | name: "ISS",
48 | long_name: Some("Instruction Specific Syndrome"),
49 | start: 0,
50 | width: 25,
51 | value: 0,
52 | description: None,
53 | subfields: vec![FieldInfo {
54 | name: "RES0",
55 | long_name: Some("Reserved"),
56 | start: 0,
57 | width: 25,
58 | value: 0,
59 | description: Some("ISS is RES0".to_string()),
60 | subfields: vec![],
61 | }],
62 | },
63 | ]
64 | );
65 | }
66 |
67 | #[test]
68 | fn data_abort() {
69 | assert_eq!(
70 | decode(0x96000050).unwrap(),
71 | vec![
72 | FieldInfo {
73 | name: "RES0",
74 | long_name: Some("Reserved"),
75 | start: 37,
76 | width: 27,
77 | value: 0,
78 | description: None,
79 | subfields: vec![],
80 | },
81 | FieldInfo {
82 | name: "ISS2",
83 | long_name: None,
84 | start: 32,
85 | width: 5,
86 | value: 0,
87 | description: None,
88 | subfields: vec![],
89 | },
90 | FieldInfo {
91 | name: "EC",
92 | long_name: Some("Exception Class"),
93 | start: 26,
94 | width: 6,
95 | value: 37,
96 | description: Some(
97 | "Data Abort taken without a change in Exception level".to_string()
98 | ),
99 | subfields: vec![],
100 | },
101 | FieldInfo {
102 | name: "IL",
103 | long_name: Some("Instruction Length"),
104 | start: 25,
105 | width: 1,
106 | value: 1,
107 | description: Some("32-bit instruction trapped".to_string()),
108 | subfields: vec![],
109 | },
110 | FieldInfo {
111 | name: "ISS",
112 | long_name: Some("Instruction Specific Syndrome"),
113 | start: 0,
114 | width: 25,
115 | value: 80,
116 | description: None,
117 | subfields: vec![
118 | FieldInfo {
119 | name: "ISV",
120 | long_name: Some("Instruction Syndrome Valid"),
121 | start: 24,
122 | width: 1,
123 | value: 0,
124 | description: Some("No valid instruction syndrome".to_string()),
125 | subfields: vec![],
126 | },
127 | FieldInfo {
128 | name: "RES0",
129 | long_name: Some("Reserved"),
130 | start: 14,
131 | width: 10,
132 | value: 0,
133 | description: None,
134 | subfields: vec![],
135 | },
136 | FieldInfo {
137 | name: "VNCR",
138 | long_name: None,
139 | start: 13,
140 | width: 1,
141 | value: 0,
142 | description: None,
143 | subfields: vec![],
144 | },
145 | FieldInfo {
146 | name: "SET",
147 | long_name: Some("Synchronous Error Type"),
148 | start: 11,
149 | width: 2,
150 | value: 0,
151 | description: Some("Recoverable state (UER)".to_string()),
152 | subfields: vec![],
153 | },
154 | FieldInfo {
155 | name: "FnV",
156 | long_name: Some("FAR not Valid"),
157 | start: 10,
158 | width: 1,
159 | value: 0,
160 | description: Some("FAR is valid".to_string()),
161 | subfields: vec![],
162 | },
163 | FieldInfo {
164 | name: "EA",
165 | long_name: Some("External abort type"),
166 | start: 9,
167 | width: 1,
168 | value: 0,
169 | description: None,
170 | subfields: vec![],
171 | },
172 | FieldInfo {
173 | name: "CM",
174 | long_name: Some("Cache Maintenance"),
175 | start: 8,
176 | width: 1,
177 | value: 0,
178 | description: None,
179 | subfields: vec![],
180 | },
181 | FieldInfo {
182 | name: "S1PTW",
183 | long_name: Some("Stage-1 translation table walk"),
184 | start: 7,
185 | width: 1,
186 | value: 0,
187 | description: None,
188 | subfields: vec![],
189 | },
190 | FieldInfo {
191 | name: "WnR",
192 | long_name: Some("Write not Read"),
193 | start: 6,
194 | width: 1,
195 | value: 1,
196 | description: Some("Abort caused by writing to memory".to_string()),
197 | subfields: vec![],
198 | },
199 | FieldInfo {
200 | name: "DFSC",
201 | long_name: Some("Data Fault Status Code"),
202 | start: 0,
203 | width: 6,
204 | value: 16,
205 | description: Some(
206 | "Synchronous External abort, not on translation table \
207 | walk or hardware update of translation table."
208 | .to_string()
209 | ),
210 | subfields: vec![],
211 | }
212 | ]
213 | },
214 | ],
215 | );
216 | }
217 |
218 | #[test]
219 | fn data_abort_isv() {
220 | assert_eq!(
221 | decode(0x97523050).unwrap(),
222 | vec![
223 | FieldInfo {
224 | name: "RES0",
225 | long_name: Some("Reserved"),
226 | start: 37,
227 | width: 27,
228 | value: 0,
229 | description: None,
230 | subfields: vec![],
231 | },
232 | FieldInfo {
233 | name: "ISS2",
234 | long_name: None,
235 | start: 32,
236 | width: 5,
237 | value: 0,
238 | description: None,
239 | subfields: vec![],
240 | },
241 | FieldInfo {
242 | name: "EC",
243 | long_name: Some("Exception Class"),
244 | start: 26,
245 | width: 6,
246 | value: 37,
247 | description: Some(
248 | "Data Abort taken without a change in Exception level".to_string()
249 | ),
250 | subfields: vec![],
251 | },
252 | FieldInfo {
253 | name: "IL",
254 | long_name: Some("Instruction Length"),
255 | start: 25,
256 | width: 1,
257 | value: 1,
258 | description: Some("32-bit instruction trapped".to_string()),
259 | subfields: vec![],
260 | },
261 | FieldInfo {
262 | name: "ISS",
263 | long_name: Some("Instruction Specific Syndrome"),
264 | start: 0,
265 | width: 25,
266 | value: 22163536,
267 | description: None,
268 | subfields: vec![
269 | FieldInfo {
270 | name: "ISV",
271 | long_name: Some("Instruction Syndrome Valid"),
272 | start: 24,
273 | width: 1,
274 | value: 1,
275 | description: Some("Valid instruction syndrome".to_string()),
276 | subfields: vec![],
277 | },
278 | FieldInfo {
279 | name: "SAS",
280 | long_name: Some("Syndrome Access Size"),
281 | start: 22,
282 | width: 2,
283 | value: 1,
284 | description: Some("halfword".to_string()),
285 | subfields: vec![],
286 | },
287 | FieldInfo {
288 | name: "SSE",
289 | long_name: Some("Syndrome Sign Extend"),
290 | start: 21,
291 | width: 1,
292 | value: 0,
293 | description: None,
294 | subfields: vec![],
295 | },
296 | FieldInfo {
297 | name: "SRT",
298 | long_name: Some("Syndrome Register Transfer"),
299 | start: 16,
300 | width: 5,
301 | value: 18,
302 | description: None,
303 | subfields: vec![],
304 | },
305 | FieldInfo {
306 | name: "SF",
307 | long_name: Some("Sixty-Four"),
308 | start: 15,
309 | width: 1,
310 | value: 0,
311 | description: Some("32-bit wide register".to_string()),
312 | subfields: vec![],
313 | },
314 | FieldInfo {
315 | name: "AR",
316 | long_name: Some("Acquire/Release"),
317 | start: 14,
318 | width: 1,
319 | value: 0,
320 | description: Some("No acquire/release semantics".to_string()),
321 | subfields: vec![],
322 | },
323 | FieldInfo {
324 | name: "VNCR",
325 | long_name: None,
326 | start: 13,
327 | width: 1,
328 | value: 1,
329 | description: None,
330 | subfields: vec![],
331 | },
332 | FieldInfo {
333 | name: "SET",
334 | long_name: Some("Synchronous Error Type"),
335 | start: 11,
336 | width: 2,
337 | value: 2,
338 | description: Some("Uncontainable (UC)".to_string()),
339 | subfields: vec![],
340 | },
341 | FieldInfo {
342 | name: "FnV",
343 | long_name: Some("FAR not Valid"),
344 | start: 10,
345 | width: 1,
346 | value: 0,
347 | description: Some("FAR is valid".to_string()),
348 | subfields: vec![],
349 | },
350 | FieldInfo {
351 | name: "EA",
352 | long_name: Some("External abort type"),
353 | start: 9,
354 | width: 1,
355 | value: 0,
356 | description: None,
357 | subfields: vec![],
358 | },
359 | FieldInfo {
360 | name: "CM",
361 | long_name: Some("Cache Maintenance"),
362 | start: 8,
363 | width: 1,
364 | value: 0,
365 | description: None,
366 | subfields: vec![],
367 | },
368 | FieldInfo {
369 | name: "S1PTW",
370 | long_name: Some("Stage-1 translation table walk"),
371 | start: 7,
372 | width: 1,
373 | value: 0,
374 | description: None,
375 | subfields: vec![],
376 | },
377 | FieldInfo {
378 | name: "WnR",
379 | long_name: Some("Write not Read"),
380 | start: 6,
381 | width: 1,
382 | value: 1,
383 | description: Some("Abort caused by writing to memory".to_string()),
384 | subfields: vec![],
385 | },
386 | FieldInfo {
387 | name: "DFSC",
388 | long_name: Some("Data Fault Status Code"),
389 | start: 0,
390 | width: 6,
391 | value: 16,
392 | description: Some(
393 | "Synchronous External abort, not on translation table \
394 | walk or hardware update of translation table."
395 | .to_string()
396 | ),
397 | subfields: vec![],
398 | }
399 | ]
400 | }
401 | ],
402 | );
403 | }
404 |
405 | #[test]
406 | fn instruction_abort() {
407 | assert_eq!(
408 | decode(0x82001e10).unwrap(),
409 | vec![
410 | FieldInfo {
411 | name: "RES0",
412 | long_name: Some("Reserved"),
413 | start: 37,
414 | width: 27,
415 | value: 0,
416 | description: None,
417 | subfields: vec![],
418 | },
419 | FieldInfo {
420 | name: "ISS2",
421 | long_name: None,
422 | start: 32,
423 | width: 5,
424 | value: 0,
425 | description: None,
426 | subfields: vec![],
427 | },
428 | FieldInfo {
429 | name: "EC",
430 | long_name: Some("Exception Class"),
431 | start: 26,
432 | width: 6,
433 | value: 32,
434 | description: Some("Instruction Abort from a lower Exception level".to_string()),
435 | subfields: vec![],
436 | },
437 | FieldInfo {
438 | name: "IL",
439 | long_name: Some("Instruction Length"),
440 | start: 25,
441 | width: 1,
442 | value: 1,
443 | description: Some("32-bit instruction trapped".to_string()),
444 | subfields: vec![],
445 | },
446 | FieldInfo {
447 | name: "ISS",
448 | long_name: Some("Instruction Specific Syndrome"),
449 | start: 0,
450 | width: 25,
451 | value: 7696,
452 | description: None,
453 | subfields: vec![
454 | FieldInfo {
455 | name: "RES0",
456 | long_name: Some("Reserved"),
457 | start: 13,
458 | width: 12,
459 | value: 0,
460 | description: None,
461 | subfields: vec![],
462 | },
463 | FieldInfo {
464 | name: "SET",
465 | long_name: Some("Synchronous Error Type"),
466 | start: 11,
467 | width: 2,
468 | value: 3,
469 | description: Some("Restartable state (UEO)".to_string()),
470 | subfields: vec![],
471 | },
472 | FieldInfo {
473 | name: "FnV",
474 | long_name: Some("FAR not Valid"),
475 | start: 10,
476 | width: 1,
477 | value: 1,
478 | description: Some(
479 | "FAR is not valid, it holds an unknown value".to_string()
480 | ),
481 | subfields: vec![],
482 | },
483 | FieldInfo {
484 | name: "EA",
485 | long_name: Some("External abort type"),
486 | start: 9,
487 | width: 1,
488 | value: 1,
489 | description: None,
490 | subfields: vec![],
491 | },
492 | FieldInfo {
493 | name: "RES0",
494 | long_name: Some("Reserved"),
495 | start: 8,
496 | width: 1,
497 | value: 0,
498 | description: None,
499 | subfields: vec![],
500 | },
501 | FieldInfo {
502 | name: "S1PTW",
503 | long_name: Some("Stage-1 translation table walk"),
504 | start: 7,
505 | width: 1,
506 | value: 0,
507 | description: None,
508 | subfields: vec![],
509 | },
510 | FieldInfo {
511 | name: "RES0",
512 | long_name: Some("Reserved"),
513 | start: 6,
514 | width: 1,
515 | value: 0,
516 | description: None,
517 | subfields: vec![],
518 | },
519 | FieldInfo {
520 | name: "IFSC",
521 | long_name: Some("Instruction Fault Status Code"),
522 | start: 0,
523 | width: 6,
524 | value: 16,
525 | description: Some(
526 | "Synchronous External abort, not on translation table \
527 | walk or hardware update of translation table."
528 | .to_string()
529 | ),
530 | subfields: vec![],
531 | }
532 | ]
533 | }
534 | ]
535 | );
536 | }
537 |
538 | #[test]
539 | fn sve() {
540 | assert_eq!(
541 | decode(0x1f300000).unwrap(),
542 | vec![
543 | FieldInfo {
544 | name: "RES0",
545 | long_name: Some("Reserved"),
546 | start: 37,
547 | width: 27,
548 | value: 0,
549 | description: None,
550 | subfields: vec![],
551 | },
552 | FieldInfo {
553 | name: "ISS2",
554 | long_name: None,
555 | start: 32,
556 | width: 5,
557 | value: 0,
558 | description: None,
559 | subfields: vec![],
560 | },
561 | FieldInfo {
562 | name: "EC",
563 | long_name: Some("Exception Class"),
564 | start: 26,
565 | width: 6,
566 | value: 7,
567 | description: Some(
568 | "Trapped access to SVE, Advanced SIMD or floating point".to_string()
569 | ),
570 | subfields: vec![]
571 | },
572 | FieldInfo {
573 | name: "IL",
574 | long_name: Some("Instruction Length"),
575 | start: 25,
576 | width: 1,
577 | value: 1,
578 | description: Some("32-bit instruction trapped".to_string()),
579 | subfields: vec![]
580 | },
581 | FieldInfo {
582 | name: "ISS",
583 | long_name: Some("Instruction Specific Syndrome"),
584 | start: 0,
585 | width: 25,
586 | value: 19922944,
587 | description: None,
588 | subfields: vec![
589 | FieldInfo {
590 | name: "CV",
591 | long_name: Some("Condition code valid"),
592 | start: 24,
593 | width: 1,
594 | value: 1,
595 | description: Some("COND is valid".to_string()),
596 | subfields: vec![]
597 | },
598 | FieldInfo {
599 | name: "COND",
600 | long_name: Some("Condition code of the trapped instruction"),
601 | start: 20,
602 | width: 4,
603 | value: 3,
604 | description: None,
605 | subfields: vec![]
606 | },
607 | FieldInfo {
608 | name: "RES0",
609 | long_name: Some("Reserved"),
610 | start: 0,
611 | width: 20,
612 | value: 0,
613 | description: None,
614 | subfields: vec![]
615 | }
616 | ]
617 | },
618 | ]
619 | );
620 | }
621 |
622 | #[test]
623 | fn ld64b() {
624 | assert_eq!(
625 | decode(0x2a000002).unwrap(),
626 | vec![
627 | FieldInfo {
628 | name: "RES0",
629 | long_name: Some("Reserved"),
630 | start: 37,
631 | width: 27,
632 | value: 0,
633 | description: None,
634 | subfields: vec![],
635 | },
636 | FieldInfo {
637 | name: "ISS2",
638 | long_name: None,
639 | start: 32,
640 | width: 5,
641 | value: 0,
642 | description: None,
643 | subfields: vec![],
644 | },
645 | FieldInfo {
646 | name: "EC",
647 | long_name: Some("Exception Class"),
648 | start: 26,
649 | width: 6,
650 | value: 10,
651 | description: Some(
652 | "Trapped execution of an LD64B, ST64B, ST64BV, or ST64BV0 instruction"
653 | .to_string()
654 | ),
655 | subfields: vec![]
656 | },
657 | FieldInfo {
658 | name: "IL",
659 | long_name: Some("Instruction Length"),
660 | start: 25,
661 | width: 1,
662 | value: 1,
663 | description: Some("32-bit instruction trapped".to_string()),
664 | subfields: vec![]
665 | },
666 | FieldInfo {
667 | name: "ISS",
668 | long_name: Some("Instruction Specific Syndrome"),
669 | start: 0,
670 | width: 25,
671 | value: 2,
672 | description: None,
673 | subfields: vec![FieldInfo {
674 | name: "ISS",
675 | long_name: None,
676 | start: 0,
677 | width: 25,
678 | value: 2,
679 | description: Some("LD64B or ST64B trapped".to_string()),
680 | subfields: vec![]
681 | }]
682 | }
683 | ]
684 | );
685 | }
686 |
--------------------------------------------------------------------------------
/src/esr/wf.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use super::common::describe_cv;
16 | use crate::{DecodeError, FieldInfo};
17 |
18 | /// Decodes the ISS value for a trapped WF* instruction.
19 | pub fn decode_iss_wf(iss: u64) -> Result, DecodeError> {
20 | let cv =
21 | FieldInfo::get_bit(iss, "CV", Some("Condition code valid"), 24).describe_bit(describe_cv);
22 | let cond = FieldInfo::get(
23 | iss,
24 | "COND",
25 | Some("Condition code of the trapped instruction"),
26 | 20,
27 | 24,
28 | );
29 | let res0a = FieldInfo::get(iss, "RES0", Some("Reserved"), 10, 20).check_res0()?;
30 | let rn = FieldInfo::get(iss, "RN", Some("Register Number"), 5, 10);
31 | let res0b = FieldInfo::get(iss, "RES0", Some("Reserved"), 3, 5).check_res0()?;
32 | let rv = FieldInfo::get_bit(iss, "RV", Some("Register Valid"), 2).describe_bit(describe_rv);
33 | let ti = FieldInfo::get(iss, "TI", Some("Trapped Instruction"), 0, 2).describe(describe_ti)?;
34 |
35 | Ok(vec![cv, cond, res0a, rn, res0b, rv, ti])
36 | }
37 |
38 | fn describe_rv(rv: bool) -> &'static str {
39 | if rv {
40 | "RN is valid"
41 | } else {
42 | "RN is not valid"
43 | }
44 | }
45 |
46 | fn describe_ti(ti: u64) -> Result<&'static str, DecodeError> {
47 | Ok(match ti {
48 | 0b00 => "WFI trapped",
49 | 0b01 => "WFE trapped",
50 | 0b10 => "WFIT trapped",
51 | 0b11 => "WFET trapped",
52 | _ => unreachable!(),
53 | })
54 | }
55 |
--------------------------------------------------------------------------------
/src/lib.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //! Library for decoding aarch64 Exception Syndrome Register and Main ID Register values.
16 |
17 | mod esr;
18 | mod midr;
19 | mod smccc;
20 |
21 | use bit_field::BitField;
22 | pub use esr::decode;
23 | pub use midr::decode_midr;
24 | pub use smccc::decode_smccc;
25 | use std::fmt::{self, Debug, Display, Formatter};
26 | use std::num::ParseIntError;
27 | use thiserror::Error;
28 |
29 | /// Information about a particular field.
30 | #[derive(Clone, Debug, Eq, PartialEq)]
31 | pub struct FieldInfo {
32 | /// The short name of the field, e.g. "ISS".
33 | pub name: &'static str,
34 | /// The long name of the field, e.g. "Instruction Specific Syndrome".
35 | pub long_name: Option<&'static str>,
36 | /// The index of the lowest bit of the field.
37 | pub start: usize,
38 | /// The number of bits in the field.
39 | pub width: usize,
40 | /// The value of the field.
41 | pub value: u64,
42 | /// A description explaining the field value, if available.
43 | pub description: Option,
44 | /// Any sub-fields.
45 | pub subfields: Vec,
46 | }
47 |
48 | impl FieldInfo {
49 | fn get(
50 | register: u64,
51 | name: &'static str,
52 | long_name: Option<&'static str>,
53 | start: usize,
54 | end: usize,
55 | ) -> Self {
56 | let value = register.get_bits(start..end);
57 | Self {
58 | name,
59 | long_name,
60 | start,
61 | width: end - start,
62 | value,
63 | description: None,
64 | subfields: vec![],
65 | }
66 | }
67 |
68 | fn get_bit(
69 | register: u64,
70 | name: &'static str,
71 | long_name: Option<&'static str>,
72 | bit: usize,
73 | ) -> Self {
74 | Self::get(register, name, long_name, bit, bit + 1)
75 | }
76 |
77 | fn with_description(self, description: String) -> Self {
78 | Self {
79 | description: Some(description),
80 | ..self
81 | }
82 | }
83 |
84 | fn as_bit(&self) -> bool {
85 | assert!(self.width == 1);
86 | self.value == 1
87 | }
88 |
89 | /// Assuming this field has a width of exactly 1, describe it with the given function.
90 | ///
91 | /// Panics if `self.width != 1`.
92 | fn describe_bit(self, describer: F) -> Self
93 | where
94 | F: FnOnce(bool) -> &'static str,
95 | {
96 | let bit = self.as_bit();
97 | let description = describer(bit).to_string();
98 | self.with_description(description)
99 | }
100 |
101 | fn describe(self, describer: F) -> Result
102 | where
103 | F: FnOnce(u64) -> Result<&'static str, DecodeError>,
104 | {
105 | let description = describer(self.value)?.to_string();
106 | Ok(self.with_description(description))
107 | }
108 |
109 | fn check_res0(self) -> Result {
110 | if self.value != 0 {
111 | Err(DecodeError::InvalidRes0 { res0: self.value })
112 | } else {
113 | Ok(self)
114 | }
115 | }
116 |
117 | /// Returns the value as a hexadecimal string, or "true" or "false" if it is a single bit.
118 | pub fn value_string(&self) -> String {
119 | if self.width == 1 {
120 | if self.value == 1 { "true" } else { "false" }.to_string()
121 | } else {
122 | format!("{:#01$x}", self.value, (self.width + 3) / 4 + 2,)
123 | }
124 | }
125 |
126 | /// Returns the value as a binary strings.
127 | pub fn value_binary_string(&self) -> String {
128 | format!("{:#01$b}", self.value, self.width + 2)
129 | }
130 | }
131 |
132 | impl Display for FieldInfo {
133 | fn fmt(&self, f: &mut Formatter) -> fmt::Result {
134 | if self.width == 1 {
135 | write!(
136 | f,
137 | "{}: {}",
138 | self.name,
139 | if self.value == 1 { "true" } else { "false" }
140 | )
141 | } else {
142 | write!(
143 | f,
144 | "{}: {} {}",
145 | self.name,
146 | self.value_string(),
147 | self.value_binary_string(),
148 | )
149 | }
150 | }
151 | }
152 |
153 | /// An error decoding a register value.
154 | #[derive(Debug, Error)]
155 | pub enum DecodeError {
156 | /// A RES0 field was not 0.
157 | #[error("Invalid ESR, res0 is {res0:#x}")]
158 | InvalidRes0 { res0: u64 },
159 | /// The EC field had an invalid value.
160 | #[error("Invalid EC {ec:#x}")]
161 | InvalidEc { ec: u64 },
162 | /// The DFSC or IFSC field had an invalid value.
163 | #[error("Invalid DFSC or IFSC {fsc:#x}")]
164 | InvalidFsc { fsc: u64 },
165 | /// The SET field had an invalid value.
166 | #[error("Invalid SET {set:#x}")]
167 | InvalidSet { set: u64 },
168 | /// The AET field had an invalid value.
169 | #[error("Invalid AET {aet:#x}")]
170 | InvalidAet { aet: u64 },
171 | /// The AM field had an invalid value.
172 | #[error("Invalid AM {am:#x}")]
173 | InvalidAm { am: u64 },
174 | /// The ISS field has an invalid value for a trapped LD64B or ST64B* exception.
175 | #[error("Invalid ISS {iss:#x} for trapped LD64B or ST64B*")]
176 | InvalidLd64bIss { iss: u64 },
177 | }
178 |
179 | /// Parses a decimal or hexadecimal number from a string.
180 | ///
181 | /// If the string starts with `"0x"` then it will be parsed as hexadecimal, otherwise it will be
182 | /// assumed to be decimal.
183 | pub fn parse_number(s: &str) -> Result {
184 | if let Some(hex) = s.strip_prefix("0x") {
185 | u64::from_str_radix(hex, 16)
186 | } else {
187 | s.parse()
188 | }
189 | }
190 |
191 | #[cfg(test)]
192 | mod tests {
193 | use super::*;
194 |
195 | #[test]
196 | fn parse_decimal() {
197 | assert_eq!(parse_number("12345"), Ok(12345));
198 | }
199 |
200 | #[test]
201 | fn parse_hex() {
202 | assert_eq!(parse_number("0x123abc"), Ok(0x123abc));
203 | }
204 |
205 | #[test]
206 | fn parse_invalid() {
207 | assert!(parse_number("123abc").is_err());
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/src/main.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use aarch64_esr_decoder::{decode, decode_midr, decode_smccc, parse_number, FieldInfo};
16 | use std::env;
17 | use std::ops::Deref;
18 | use std::process::exit;
19 |
20 | fn main() {
21 | let args = match parse_args() {
22 | Ok(args) => args,
23 | Err(error_code) => exit(error_code),
24 | };
25 |
26 | let value = parse_number(&args.value).unwrap();
27 | let decoded = match args.mode {
28 | Mode::Esr => {
29 | println!("ESR {:#034x}:", value);
30 | decode(value).unwrap()
31 | }
32 | Mode::Midr => {
33 | println!("MIDR {:#034x}:", value);
34 | decode_midr(value).unwrap()
35 | }
36 | Mode::Smccc => {
37 | println!("SMC ID {:#018x}:", value);
38 | decode_smccc(value).unwrap()
39 | }
40 | };
41 | print_decoded(&decoded, args.verbose, 0);
42 | }
43 |
44 | fn print_decoded(fields: &[FieldInfo], verbose: bool, level: usize) {
45 | let indentation = " ".repeat(level * 2);
46 | for field in fields {
47 | let verbose_name = match field.long_name {
48 | Some(long_name) if verbose => format!(" ({})", long_name),
49 | _ => "".to_string(),
50 | };
51 | if field.width == 1 {
52 | println!(
53 | "{}{:02} {}{}",
54 | indentation, field.start, field, verbose_name
55 | );
56 | } else {
57 | println!(
58 | "{}{:02}..{:02} {}{}",
59 | indentation,
60 | field.start,
61 | field.start + field.width - 1,
62 | field,
63 | verbose_name,
64 | );
65 | }
66 | if let Some(description) = &field.description {
67 | println!("{} # {}", indentation, description);
68 | }
69 |
70 | print_decoded(&field.subfields, verbose, level + 1);
71 | }
72 | }
73 |
74 | /// Parse and return command-line arguments, or an error code to return.
75 | fn parse_args() -> Result {
76 | let args: Vec = env::args().collect();
77 | let args: Vec<&str> = args.iter().map(Deref::deref).collect();
78 | match args.as_slice() {
79 | [_, esr] => Ok(Args {
80 | verbose: false,
81 | mode: Mode::Esr,
82 | value: esr.to_string(),
83 | }),
84 | [_, "-v", esr] => Ok(Args {
85 | verbose: true,
86 | mode: Mode::Esr,
87 | value: esr.to_string(),
88 | }),
89 | [_, "midr", midr] => Ok(Args {
90 | verbose: false,
91 | mode: Mode::Midr,
92 | value: midr.to_string(),
93 | }),
94 | [_, "-v", "midr", midr] => Ok(Args {
95 | verbose: true,
96 | mode: Mode::Midr,
97 | value: midr.to_string(),
98 | }),
99 | [_, "smccc", smccc] => Ok(Args {
100 | verbose: false,
101 | mode: Mode::Smccc,
102 | value: smccc.to_string(),
103 | }),
104 | [_, "-v", "smccc", smccc] => Ok(Args {
105 | verbose: true,
106 | mode: Mode::Smccc,
107 | value: smccc.to_string(),
108 | }),
109 | _ => {
110 | eprintln!("Usage:");
111 | eprintln!(" {} [-v] ", args[0]);
112 | eprintln!(" {} [-v] midr ", args[0]);
113 | eprintln!(" {} [-v] smccc ", args[0]);
114 | Err(1)
115 | }
116 | }
117 | }
118 |
119 | /// Command-line arguments.
120 | #[derive(Clone, Debug, Eq, PartialEq)]
121 | struct Args {
122 | verbose: bool,
123 | mode: Mode,
124 | value: String,
125 | }
126 |
127 | #[derive(Copy, Clone, Debug, Eq, PartialEq)]
128 | enum Mode {
129 | Esr,
130 | Midr,
131 | Smccc,
132 | }
133 |
--------------------------------------------------------------------------------
/src/midr.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use super::{DecodeError, FieldInfo};
16 |
17 | /// Decodes the given Main ID Register value, or returns an error if it is not valid.
18 | pub fn decode_midr(midr: u64) -> Result, DecodeError> {
19 | let res0 = FieldInfo::get(midr, "RES0", Some("Reserved"), 32, 64).check_res0()?;
20 | let implementer =
21 | FieldInfo::get(midr, "Implementer", None, 24, 32).describe(describe_implementer)?;
22 | let variant = FieldInfo::get(midr, "Variant", None, 20, 24);
23 | let architecture =
24 | FieldInfo::get(midr, "Architecture", None, 16, 20).describe(describe_architecture)?;
25 | let part_num = FieldInfo::get(midr, "PartNum", Some("Part number"), 4, 16);
26 | let revision = FieldInfo::get(midr, "Revision", None, 0, 4);
27 |
28 | Ok(vec![
29 | res0,
30 | implementer,
31 | variant,
32 | architecture,
33 | part_num,
34 | revision,
35 | ])
36 | }
37 |
38 | fn describe_implementer(implementer: u64) -> Result<&'static str, DecodeError> {
39 | Ok(match implementer {
40 | 0x00 => "Reserved for software use",
41 | 0xC0 => "Ampere Computing",
42 | 0x41 => "Arm Limited",
43 | 0x42 => "Broadcom Corporation",
44 | 0x43 => "Cavium Inc.",
45 | 0x44 => "Digital Equipment Corporation",
46 | 0x46 => "Fujitsu Ltd.",
47 | 0x49 => "Infineon Technologies AG",
48 | 0x4D => "Motorola or Freescale Semiconductor Inc.",
49 | 0x4E => "NVIDIA Corporation",
50 | 0x50 => "Applied Micro Circuits Corporation",
51 | 0x51 => "Qualcomm Inc.",
52 | 0x56 => "Marvell International Ltd.",
53 | 0x69 => "Intel Corporation",
54 | _ => "Unknown",
55 | })
56 | }
57 |
58 | fn describe_architecture(architecture: u64) -> Result<&'static str, DecodeError> {
59 | Ok(match architecture {
60 | 0b0001 => "Armv4",
61 | 0b0010 => "Armv4T",
62 | 0b0011 => "Armv5",
63 | 0b0100 => "Armv5T",
64 | 0b0101 => "Armv5TE",
65 | 0b0110 => "Armv5TEJ",
66 | 0b0111 => "Armv6",
67 | 0b1111 => "Architectural features are individually identified",
68 | _ => "Reserved",
69 | })
70 | }
71 |
--------------------------------------------------------------------------------
/src/smccc.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Decoder for SMC Calling Convention ARM DEN 0028E v1.4
16 |
17 | mod arm;
18 | mod common;
19 | mod ffa;
20 | mod hyp;
21 | mod secure;
22 | mod tapp;
23 |
24 | use arm::decode_arm_service;
25 | use common::decode_common_service;
26 | use common::describe_general32_queries;
27 | use common::reserved_fids;
28 | use common::smccc_general32_queries;
29 | use hyp::decode_hyp_service;
30 | use secure::decode_secure_service;
31 | use tapp::decode_tapp_service;
32 |
33 | use super::{DecodeError, FieldInfo};
34 |
35 | /// Decodes the function ID of an SMCCC (ARM DEN 0028E v1.4) call, or returns an error if it is not valid.
36 | pub fn decode_smccc(smccc: u64) -> Result, DecodeError> {
37 | let call_type = FieldInfo::get(smccc, "Call Type", None, 31, 32).describe(describe_call)?;
38 |
39 | let result = if call_type.value == 1 {
40 | parse_fastcall(smccc)?
41 | } else {
42 | parse_yieldcall(smccc)?
43 | };
44 |
45 | Ok([vec![call_type], result].concat())
46 | }
47 |
48 | pub fn parse_fastcall(smccc: u64) -> Result, DecodeError> {
49 | let call_convention =
50 | FieldInfo::get(smccc, "Call Convention", None, 30, 31).describe(describe_convention)?;
51 | let service_call =
52 | FieldInfo::get(smccc, "Service Call", None, 24, 30).describe(describe_service)?;
53 |
54 | let mbz = FieldInfo::get(
55 | smccc,
56 | "MBZ",
57 | Some("Some legacy Armv7 set this to 1"),
58 | 17,
59 | 24,
60 | );
61 | let sve = FieldInfo::get(
62 | smccc,
63 | "SVE live state",
64 | Some("No live state[1] From SMCCCv1.3, before SMCCCv1.3 MBZ"),
65 | 16,
66 | 17,
67 | );
68 |
69 | let function_number = match service_call.value {
70 | 0x00 => decode_arm_service(smccc, call_convention.value)?,
71 | 0x04 => decode_secure_service(smccc, call_convention.value)?,
72 | 0x05 => decode_hyp_service(smccc, call_convention.value)?,
73 | 0x30..=0x31 => decode_tapp_service(smccc, call_convention.value)?,
74 | _ => decode_common_service(smccc, call_convention.value)?,
75 | };
76 |
77 | Ok(vec![
78 | call_convention,
79 | service_call,
80 | mbz,
81 | sve,
82 | function_number,
83 | ])
84 | }
85 | pub fn parse_yieldcall(smccc: u64) -> Result, DecodeError> {
86 | let yield_type =
87 | FieldInfo::get(smccc, "Service Type", None, 0, 31).describe(describe_yield_service)?;
88 | Ok(vec![yield_type])
89 | }
90 |
91 | fn describe_yield_service(service: u64) -> Result<&'static str, DecodeError> {
92 | Ok(match service {
93 | 0x00000000..=0x0100FFFF => {
94 | "Reserved for existing APIs (in use by the existing Armv7 devices)"
95 | }
96 | 0x02000000..=0x1FFFFFFF => "Trusted OS Yielding Calls",
97 | 0x20000000..=0x7FFFFFFF => "Reserved for future expansion of Trusted OS Yielding Calls",
98 | _ => "Unknown",
99 | })
100 | }
101 |
102 | fn describe_call(call: u64) -> Result<&'static str, DecodeError> {
103 | Ok(match call {
104 | 0x00 => "Yielding Call",
105 | 0x01 => "Fast Call",
106 | _ => "Unknown",
107 | })
108 | }
109 | fn describe_convention(conv: u64) -> Result<&'static str, DecodeError> {
110 | Ok(match conv {
111 | 0x00 => "SMC32/HVC32",
112 | 0x01 => "SMC64/HVC64",
113 | _ => "Unknown",
114 | })
115 | }
116 | fn describe_service(service: u64) -> Result<&'static str, DecodeError> {
117 | Ok(match service {
118 | 0x00 => "Arm Architecture Call",
119 | 0x01 => "CPU Service Call",
120 | 0x02 => "SiP Service Call",
121 | 0x03 => "OEM Service Call",
122 | 0x04 => "Standard Secure Service Call",
123 | 0x05 => "Standard Hypervisor Service Call",
124 | 0x06 => "Vendor Specific Hypervisor Service Call",
125 | 0x07..=0x2F => "Reserved for future use",
126 | 0x30..=0x31 => "Trusted Application Call",
127 | 0x32..=0x3F => "Trusted OS Call",
128 | _ => "Unknown",
129 | })
130 | }
131 |
--------------------------------------------------------------------------------
/src/smccc/arm.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use super::{reserved_fids, DecodeError, FieldInfo};
16 |
17 | pub fn decode_arm_service(smccc: u64, conv: u64) -> Result {
18 | if conv == 0 {
19 | FieldInfo::get(smccc, "Function Number", None, 0, 16).describe(describe_arm32_service)
20 | } else {
21 | FieldInfo::get(smccc, "Function Number", None, 0, 16).describe(describe_arm64_service)
22 | }
23 | }
24 |
25 | fn describe_arm32_service(service: u64) -> Result<&'static str, DecodeError> {
26 | Ok(match service {
27 | 0x0000 => "SMCCC_VERSION",
28 | 0x0001 => "SMCCC_ARCH_FEATURES",
29 | 0x0002 => "SMCCC_ARCH_SOC_ID",
30 | 0x3FFF => "SMCCC_ARCH_WORKAROUND_3",
31 | 0x7FFF => "SMCCC_ARCH_WORKAROUND_2",
32 | 0x8000 => "SMCCC_ARCH_WORKAROUND_1",
33 | 0xFF00 => "Call Count Query, deprecated from SMCCCv1.2",
34 | 0xFF01 => "Call UUID Query, deprecated from SMCCCv1.2",
35 | 0xFF03 => "Revision Query, deprecated from SMCCCv1.2",
36 | _ => reserved_fids(service),
37 | })
38 | }
39 | fn describe_arm64_service(service: u64) -> Result<&'static str, DecodeError> {
40 | Ok(reserved_fids(service))
41 | }
42 |
--------------------------------------------------------------------------------
/src/smccc/common.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use super::{DecodeError, FieldInfo};
16 |
17 | pub fn decode_common_service(smccc: u64, conv: u64) -> Result {
18 | if conv == 0 {
19 | FieldInfo::get(smccc, "Function Number", None, 0, 16).describe(describe_general32_queries)
20 | } else {
21 | FieldInfo::get(smccc, "Function Number", None, 0, 16).describe(describe_general64_queries)
22 | }
23 | }
24 |
25 | pub fn reserved_fids(service: u64) -> &'static str {
26 | match service {
27 | 0xFF00..=0xFFFF => "Reserved for future expansion",
28 | _ => "",
29 | }
30 | }
31 |
32 | pub fn smccc_general32_queries(service: u64) -> &'static str {
33 | match service {
34 | 0xFF00 => "Call Count Query, deprecated from SMCCCv1.2",
35 | 0xFF01 => "Call UUID Query",
36 | 0xFF03 => "Revision Query",
37 | _ => reserved_fids(service),
38 | }
39 | }
40 | pub fn describe_general32_queries(service: u64) -> Result<&'static str, DecodeError> {
41 | Ok(smccc_general32_queries(service))
42 | }
43 | pub fn describe_general64_queries(service: u64) -> Result<&'static str, DecodeError> {
44 | Ok(reserved_fids(service))
45 | }
46 |
--------------------------------------------------------------------------------
/src/smccc/ffa.rs:
--------------------------------------------------------------------------------
1 | const FFA_ERROR: u64 = 0x60;
2 | const FFA_SUCCESS: u64 = 0x61;
3 | const FFA_INTERRUPT: u64 = 0x62;
4 | const FFA_VERSION: u64 = 0x63;
5 | const FFA_FEATURES: u64 = 0x64;
6 | const FFA_RX_RELEASE: u64 = 0x65;
7 | const FFA_RXTX_MAP: u64 = 0x66;
8 | const FFA_RXTX_UNMAP: u64 = 0x67;
9 | const FFA_PARTITION_INFO_GET: u64 = 0x68;
10 | const FFA_ID_GET: u64 = 0x69;
11 | const FFA_MSG_POLL: u64 = 0x6A;
12 | const FFA_MSG_WAIT: u64 = 0x6B;
13 | const FFA_YIELD: u64 = 0x6C;
14 | const FFA_RUN: u64 = 0x6D;
15 | const FFA_MSG_SEND: u64 = 0x6E;
16 | const FFA_MSG_SEND_DIRECT_REQ: u64 = 0x6F;
17 | const FFA_MSG_SEND_DIRECT_RESP: u64 = 0x70;
18 | const FFA_MEM_DONATE: u64 = 0x71;
19 | const FFA_MEM_LEND: u64 = 0x72;
20 | const FFA_MEM_SHARE: u64 = 0x73;
21 | const FFA_MEM_RETRIEVE_REQ: u64 = 0x74;
22 | const FFA_MEM_RETRIEVE_RESP: u64 = 0x75;
23 | const FFA_MEM_RELINQUISH: u64 = 0x76;
24 | const FFA_MEM_RECLAIM: u64 = 0x77;
25 | const FFA_MEM_OP_PAUSE: u64 = 0x78;
26 | const FFA_MEM_OP_RESUME: u64 = 0x79;
27 | const FFA_MEM_FRAG_RX: u64 = 0x7A;
28 | const FFA_MEM_FRAG_TX: u64 = 0x7B;
29 | const FFA_NORMAL_WORLD_RESUME: u64 = 0x7C;
30 |
31 | pub fn ffa_32_function_id(function: u64) -> Option<&'static str> {
32 | match function {
33 | FFA_ERROR => Some("FFA_ERROR_32"),
34 | FFA_SUCCESS => Some("FFA_SUCCESS_32"),
35 | FFA_INTERRUPT => Some("FFA_INTERRUPT_32"),
36 | FFA_VERSION => Some("FFA_VERSION_32"),
37 | FFA_FEATURES => Some("FFA_FEATURES_32"),
38 | FFA_RX_RELEASE => Some("FFA_RX_RELEASE_32"),
39 | FFA_RXTX_MAP => Some("FFA_RXTX_MAP_32"),
40 | FFA_RXTX_UNMAP => Some("FFA_RXTX_UNMAP_32"),
41 | FFA_PARTITION_INFO_GET => Some("FFA_PARTITION_INFO_GET_32"),
42 | FFA_ID_GET => Some("FFA_ID_GET_32"),
43 | FFA_MSG_POLL => Some("FFA_MSG_POLL_32"),
44 | FFA_MSG_WAIT => Some("FFA_MSG_WAIT_32"),
45 | FFA_YIELD => Some("FFA_YIELD_32"),
46 | FFA_RUN => Some("FFA_RUN_32"),
47 | FFA_MSG_SEND => Some("FFA_MSG_SEND_32"),
48 | FFA_MSG_SEND_DIRECT_REQ => Some("FFA_MSG_SEND_DIRECT_REQ_32"),
49 | FFA_MSG_SEND_DIRECT_RESP => Some("FFA_MSG_SEND_DIRECT_RESP_32"),
50 | FFA_MEM_DONATE => Some("FFA_MEM_DONATE_32"),
51 | FFA_MEM_LEND => Some("FFA_MEM_LEND_32"),
52 | FFA_MEM_SHARE => Some("FFA_MEM_SHARE_32"),
53 | FFA_MEM_RETRIEVE_REQ => Some("FFA_MEM_RETRIEVE_REQ_32"),
54 | FFA_MEM_RETRIEVE_RESP => Some("FFA_MEM_RETRIEVE_RESP_32"),
55 | FFA_MEM_RELINQUISH => Some("FFA_MEM_RELINQUISH_32"),
56 | FFA_MEM_RECLAIM => Some("FFA_MEM_RECLAIM_32"),
57 | FFA_MEM_OP_PAUSE => Some("FFA_MEM_OP_PAUSE"),
58 | FFA_MEM_OP_RESUME => Some("FFA_MEM_OP_RESUME"),
59 | FFA_MEM_FRAG_RX => Some("FFA_MEM_FRAG_RX_32"),
60 | FFA_MEM_FRAG_TX => Some("FFA_MEM_FRAG_TX_32"),
61 | FFA_NORMAL_WORLD_RESUME => Some("FFA_NORMAL_WORLD_RESUME"),
62 | _ => None,
63 | }
64 | }
65 |
66 | pub fn ffa_64_function_id(function: u64) -> Option<&'static str> {
67 | match function {
68 | FFA_RXTX_MAP => Some("FFA_RXTX_MAP_64"),
69 | FFA_MSG_SEND_DIRECT_REQ => Some("FFA_MSG_SEND_DIRECT_REQ_64"),
70 | FFA_MSG_SEND_DIRECT_RESP => Some("FFA_MSG_SEND_DIRECT_RESP_64"),
71 | FFA_MEM_DONATE => Some("FFA_MEM_DONATE_64"),
72 | FFA_MEM_LEND => Some("FFA_MEM_LEND_64"),
73 | FFA_MEM_SHARE => Some("FFA_MEM_SHARE_64"),
74 | FFA_MEM_RETRIEVE_REQ => Some("FFA_MEM_RETRIEVE_REQ_64"),
75 | _ => None,
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/smccc/hyp.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use super::{describe_general32_queries, DecodeError, FieldInfo};
16 |
17 | pub fn decode_hyp_service(smccc: u64, conv: u64) -> Result {
18 | if conv == 0 {
19 | FieldInfo::get(smccc, "Function Number", None, 0, 16).describe(describe_general32_queries)
20 | } else {
21 | FieldInfo::get(smccc, "Function Number", None, 0, 16).describe(describe_hyp64_service)
22 | }
23 | }
24 |
25 | fn describe_hyp64_service(service: u64) -> Result<&'static str, DecodeError> {
26 | Ok(match service {
27 | 0x20..=0x3F => "PV Time 64-bit calls",
28 | _ => "",
29 | })
30 | }
31 |
--------------------------------------------------------------------------------
/src/smccc/secure.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use super::{
16 | ffa::{ffa_32_function_id, ffa_64_function_id},
17 | smccc_general32_queries, DecodeError, FieldInfo,
18 | };
19 |
20 | pub fn decode_secure_service(smccc: u64, conv: u64) -> Result {
21 | let info = if conv == 0 {
22 | FieldInfo::get(smccc, "Function Number", None, 0, 16).describe(describe_secure32_service)?
23 | } else {
24 | FieldInfo::get(smccc, "Function Number", None, 0, 16).describe(describe_secure64_service)?
25 | };
26 | Ok(info)
27 | }
28 |
29 | fn secure_service(service: u64) -> &'static str {
30 | match service {
31 | 0x000..=0x01F => "PSCI Call (Power Secure Control Interface)",
32 | 0x020..=0x03F => "SDEI Call (Software Delegated Exception Interface)",
33 | 0x040..=0x04F => "MM Call (Management Mode)",
34 | 0x050..=0x05F => "TRNG Call",
35 | 0x060..=0x0EF => "Unknown FF-A Call",
36 | 0x0F0..=0x10F => "Errata Call",
37 | 0x150..=0x1CF => "CCA Call",
38 | _ => "",
39 | }
40 | }
41 |
42 | fn describe_secure32_service(service: u64) -> Result<&'static str, DecodeError> {
43 | if let Some(ffa_call) = ffa_32_function_id(service) {
44 | return Ok(ffa_call);
45 | }
46 |
47 | Ok(match service {
48 | 0x000..=0x1CF => secure_service(service),
49 | _ => smccc_general32_queries(service),
50 | })
51 | }
52 | fn describe_secure64_service(service: u64) -> Result<&'static str, DecodeError> {
53 | if let Some(ffa_call) = ffa_64_function_id(service) {
54 | return Ok(ffa_call);
55 | }
56 | Ok(secure_service(service))
57 | }
58 |
--------------------------------------------------------------------------------
/src/smccc/tapp.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2022 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | use super::{DecodeError, FieldInfo};
16 |
17 | pub fn decode_tapp_service(smccc: u64, _conv: u64) -> Result {
18 | Ok(FieldInfo::get(smccc, "Function Number", None, 0, 16))
19 | }
20 |
--------------------------------------------------------------------------------