1use alloc::vec::Vec;
24
25use crate::ecall::{EcallHandler, EcallKind, EcallResult};
26use crate::exit::ExitReason;
27use crate::gas::GasCounter;
28use crate::instruction::Inst;
29use crate::mem::{Memory, perm};
30use crate::predecode::{Predecode, RvPreDecodedInst, predecode};
31use crate::regs::Regs;
32
33#[derive(Debug)]
37pub struct Program {
38 pub code: Vec<u8>,
39 pub predecode: Predecode,
40 pub code_base: u32,
45}
46
47impl Program {
48 pub fn new(code: Vec<u8>, code_base: u32) -> Self {
51 let predecode = predecode(&code);
52 Self {
53 code,
54 predecode,
55 code_base,
56 }
57 }
58}
59
60pub struct Interpreter;
62
63impl Interpreter {
64 #[inline]
67 pub fn run_program<M: Memory>(
68 program: &Program,
69 regs: &mut Regs,
70 mem: &mut M,
71 gas: &mut GasCounter,
72 handler: &mut dyn EcallHandler,
73 ) -> ExitReason {
74 Self::run(
75 &program.predecode,
76 &program.code,
77 program.code_base,
78 regs,
79 mem,
80 gas,
81 handler,
82 )
83 }
84
85 pub fn run<M: Memory>(
90 predecode: &Predecode,
91 code: &[u8],
92 code_base: u32,
93 regs: &mut Regs,
94 mem: &mut M,
95 gas: &mut GasCounter,
96 handler: &mut dyn EcallHandler,
97 ) -> ExitReason {
98 let insts: &[RvPreDecodedInst] = &predecode.insts;
104 if insts.is_empty() {
105 return ExitReason::Panic;
106 }
107
108 let mut idx = match find_idx_for_pc(insts, regs.pc as u32) {
118 Some(i) if insts[i].is_gas_block_start => i,
119 _ => return ExitReason::Panic,
120 };
121
122 loop {
123 let inst = unsafe { insts.get_unchecked(idx) };
124
125 if inst.is_gas_block_start {
133 let cost = predecode.block_costs[idx] as u64;
134 if cost != 0 {
135 let reserve = predecode.block_reserves[idx] as u64;
136 if gas.remaining() < cost + reserve {
137 regs.pc = inst.pc as u64;
138 return ExitReason::OutOfGas;
139 }
140 gas.charge(cost).expect("gas pre-reserved at block entry");
141 }
142 }
143
144 let pc = inst.pc;
145 let next_pc = inst.next_pc;
146
147 let mut next_idx_override: Option<usize> = None;
151
152 match inst.inst {
153 Inst::Lb { rd, rs1, imm } => {
155 let addr = compute_addr(regs, rs1, imm);
156 if mem.touch_read(addr, 1, gas).is_err() {
157 return page_fault(regs, pc, addr);
158 }
159 match load_u8(mem, code, code_base, addr) {
160 Some(v) => reg_write(regs, rd, v as i8 as i64 as u64),
161 None => return page_fault(regs, pc, addr),
162 }
163 }
164 Inst::Lh { rd, rs1, imm } => {
165 let addr = compute_addr(regs, rs1, imm);
166 if mem.touch_read(addr, 2, gas).is_err() {
167 return page_fault(regs, pc, addr);
168 }
169 match load_u16(mem, code, code_base, addr) {
170 Some(v) => reg_write(regs, rd, v as i16 as i64 as u64),
171 None => return page_fault(regs, pc, addr),
172 }
173 }
174 Inst::Lw { rd, rs1, imm } => {
175 let addr = compute_addr(regs, rs1, imm);
176 if mem.touch_read(addr, 4, gas).is_err() {
177 return page_fault(regs, pc, addr);
178 }
179 match load_u32(mem, code, code_base, addr) {
180 Some(v) => reg_write(regs, rd, v as i32 as i64 as u64),
181 None => return page_fault(regs, pc, addr),
182 }
183 }
184 Inst::Ld { rd, rs1, imm } => {
185 let addr = compute_addr(regs, rs1, imm);
186 if mem.touch_read(addr, 8, gas).is_err() {
187 return page_fault(regs, pc, addr);
188 }
189 match load_u64(mem, code, code_base, addr) {
190 Some(v) => reg_write(regs, rd, v),
191 None => return page_fault(regs, pc, addr),
192 }
193 }
194 Inst::Lbu { rd, rs1, imm } => {
195 let addr = compute_addr(regs, rs1, imm);
196 if mem.touch_read(addr, 1, gas).is_err() {
197 return page_fault(regs, pc, addr);
198 }
199 match load_u8(mem, code, code_base, addr) {
200 Some(v) => reg_write(regs, rd, v as u64),
201 None => return page_fault(regs, pc, addr),
202 }
203 }
204 Inst::Lhu { rd, rs1, imm } => {
205 let addr = compute_addr(regs, rs1, imm);
206 if mem.touch_read(addr, 2, gas).is_err() {
207 return page_fault(regs, pc, addr);
208 }
209 match load_u16(mem, code, code_base, addr) {
210 Some(v) => reg_write(regs, rd, v as u64),
211 None => return page_fault(regs, pc, addr),
212 }
213 }
214 Inst::Lwu { rd, rs1, imm } => {
215 let addr = compute_addr(regs, rs1, imm);
216 if mem.touch_read(addr, 4, gas).is_err() {
217 return page_fault(regs, pc, addr);
218 }
219 match load_u32(mem, code, code_base, addr) {
220 Some(v) => reg_write(regs, rd, v as u64),
221 None => return page_fault(regs, pc, addr),
222 }
223 }
224
225 Inst::Sb { rs1, rs2, imm } => {
227 let addr = compute_addr(regs, rs1, imm);
228 if mem.touch_write(addr, 1, gas).is_err()
229 || !store_writable(mem, addr, 1)
230 || !mem.write_u8(addr, reg_read(regs, rs2) as u8)
231 {
232 return page_fault(regs, pc, addr);
233 }
234 }
235 Inst::Sh { rs1, rs2, imm } => {
236 let addr = compute_addr(regs, rs1, imm);
237 if mem.touch_write(addr, 2, gas).is_err()
238 || !store_writable(mem, addr, 2)
239 || !mem.write_u16_le(addr, reg_read(regs, rs2) as u16)
240 {
241 return page_fault(regs, pc, addr);
242 }
243 }
244 Inst::Sw { rs1, rs2, imm } => {
245 let addr = compute_addr(regs, rs1, imm);
246 if mem.touch_write(addr, 4, gas).is_err()
247 || !store_writable(mem, addr, 4)
248 || !mem.write_u32_le(addr, reg_read(regs, rs2) as u32)
249 {
250 return page_fault(regs, pc, addr);
251 }
252 }
253 Inst::Sd { rs1, rs2, imm } => {
254 let addr = compute_addr(regs, rs1, imm);
255 if mem.touch_write(addr, 8, gas).is_err()
256 || !store_writable(mem, addr, 8)
257 || !mem.write_u64_le(addr, reg_read(regs, rs2))
258 {
259 return page_fault(regs, pc, addr);
260 }
261 }
262
263 Inst::Addi { rd, rs1, imm } => {
265 let v = reg_read(regs, rs1).wrapping_add(imm as i64 as u64);
266 reg_write(regs, rd, v);
267 }
268 Inst::Slti { rd, rs1, imm } => {
269 let v = ((reg_read(regs, rs1) as i64) < (imm as i64)) as u64;
270 reg_write(regs, rd, v);
271 }
272 Inst::Sltiu { rd, rs1, imm } => {
273 let v = (reg_read(regs, rs1) < (imm as i64 as u64)) as u64;
274 reg_write(regs, rd, v);
275 }
276 Inst::Andi { rd, rs1, imm } => {
277 let v = reg_read(regs, rs1) & (imm as i64 as u64);
278 reg_write(regs, rd, v);
279 }
280 Inst::Ori { rd, rs1, imm } => {
281 let v = reg_read(regs, rs1) | (imm as i64 as u64);
282 reg_write(regs, rd, v);
283 }
284 Inst::Xori { rd, rs1, imm } => {
285 let v = reg_read(regs, rs1) ^ (imm as i64 as u64);
286 reg_write(regs, rd, v);
287 }
288 Inst::Slli { rd, rs1, shamt } => {
289 reg_write(
290 regs,
291 rd,
292 reg_read(regs, rs1).wrapping_shl(shamt as u32 & 63),
293 );
294 }
295 Inst::Srli { rd, rs1, shamt } => {
296 reg_write(
297 regs,
298 rd,
299 reg_read(regs, rs1).wrapping_shr(shamt as u32 & 63),
300 );
301 }
302 Inst::Srai { rd, rs1, shamt } => {
303 let v = (reg_read(regs, rs1) as i64).wrapping_shr(shamt as u32 & 63);
304 reg_write(regs, rd, v as u64);
305 }
306
307 Inst::Addiw { rd, rs1, imm } => {
309 let v = (reg_read(regs, rs1) as i32).wrapping_add(imm);
310 reg_write(regs, rd, v as i64 as u64);
311 }
312 Inst::Slliw { rd, rs1, shamt } => {
313 let v = (reg_read(regs, rs1) as u32).wrapping_shl(shamt as u32 & 31);
314 reg_write(regs, rd, v as i32 as i64 as u64);
315 }
316 Inst::Srliw { rd, rs1, shamt } => {
317 let v = (reg_read(regs, rs1) as u32).wrapping_shr(shamt as u32 & 31);
318 reg_write(regs, rd, v as i32 as i64 as u64);
319 }
320 Inst::Sraiw { rd, rs1, shamt } => {
321 let v = (reg_read(regs, rs1) as i32).wrapping_shr(shamt as u32 & 31);
322 reg_write(regs, rd, v as i64 as u64);
323 }
324
325 Inst::Add { rd, rs1, rs2 } => {
327 let v = reg_read(regs, rs1).wrapping_add(reg_read(regs, rs2));
328 reg_write(regs, rd, v);
329 }
330 Inst::Sub { rd, rs1, rs2 } => {
331 let v = reg_read(regs, rs1).wrapping_sub(reg_read(regs, rs2));
332 reg_write(regs, rd, v);
333 }
334 Inst::Sll { rd, rs1, rs2 } => {
335 let s = reg_read(regs, rs2) as u32 & 63;
336 reg_write(regs, rd, reg_read(regs, rs1).wrapping_shl(s));
337 }
338 Inst::Srl { rd, rs1, rs2 } => {
339 let s = reg_read(regs, rs2) as u32 & 63;
340 reg_write(regs, rd, reg_read(regs, rs1).wrapping_shr(s));
341 }
342 Inst::Sra { rd, rs1, rs2 } => {
343 let s = reg_read(regs, rs2) as u32 & 63;
344 reg_write(
345 regs,
346 rd,
347 (reg_read(regs, rs1) as i64).wrapping_shr(s) as u64,
348 );
349 }
350 Inst::Slt { rd, rs1, rs2 } => {
351 let v = ((reg_read(regs, rs1) as i64) < (reg_read(regs, rs2) as i64)) as u64;
352 reg_write(regs, rd, v);
353 }
354 Inst::Sltu { rd, rs1, rs2 } => {
355 let v = (reg_read(regs, rs1) < reg_read(regs, rs2)) as u64;
356 reg_write(regs, rd, v);
357 }
358 Inst::Xor { rd, rs1, rs2 } => {
359 reg_write(regs, rd, reg_read(regs, rs1) ^ reg_read(regs, rs2));
360 }
361 Inst::Or { rd, rs1, rs2 } => {
362 reg_write(regs, rd, reg_read(regs, rs1) | reg_read(regs, rs2));
363 }
364 Inst::And { rd, rs1, rs2 } => {
365 reg_write(regs, rd, reg_read(regs, rs1) & reg_read(regs, rs2));
366 }
367
368 Inst::Addw { rd, rs1, rs2 } => {
370 let v = (reg_read(regs, rs1) as i32).wrapping_add(reg_read(regs, rs2) as i32);
371 reg_write(regs, rd, v as i64 as u64);
372 }
373 Inst::Subw { rd, rs1, rs2 } => {
374 let v = (reg_read(regs, rs1) as i32).wrapping_sub(reg_read(regs, rs2) as i32);
375 reg_write(regs, rd, v as i64 as u64);
376 }
377 Inst::Sllw { rd, rs1, rs2 } => {
378 let s = reg_read(regs, rs2) as u32 & 31;
379 let v = (reg_read(regs, rs1) as u32).wrapping_shl(s);
380 reg_write(regs, rd, v as i32 as i64 as u64);
381 }
382 Inst::Srlw { rd, rs1, rs2 } => {
383 let s = reg_read(regs, rs2) as u32 & 31;
384 let v = (reg_read(regs, rs1) as u32).wrapping_shr(s);
385 reg_write(regs, rd, v as i32 as i64 as u64);
386 }
387 Inst::Sraw { rd, rs1, rs2 } => {
388 let s = reg_read(regs, rs2) as u32 & 31;
389 let v = (reg_read(regs, rs1) as i32).wrapping_shr(s);
390 reg_write(regs, rd, v as i64 as u64);
391 }
392
393 Inst::Mul { rd, rs1, rs2 } => {
395 let v = reg_read(regs, rs1).wrapping_mul(reg_read(regs, rs2));
396 reg_write(regs, rd, v);
397 }
398 Inst::Mulh { rd, rs1, rs2 } => {
399 let a = reg_read(regs, rs1) as i64 as i128;
400 let b = reg_read(regs, rs2) as i64 as i128;
401 reg_write(regs, rd, ((a * b) >> 64) as u64);
402 }
403 Inst::Mulhsu { rd, rs1, rs2 } => {
404 let a = reg_read(regs, rs1) as i64 as i128;
405 let b = reg_read(regs, rs2) as u128 as i128;
406 reg_write(regs, rd, ((a * b) >> 64) as u64);
407 }
408 Inst::Mulhu { rd, rs1, rs2 } => {
409 let a = reg_read(regs, rs1) as u128;
410 let b = reg_read(regs, rs2) as u128;
411 reg_write(regs, rd, ((a * b) >> 64) as u64);
412 }
413 Inst::Div { rd, rs1, rs2 } => {
414 let a = reg_read(regs, rs1) as i64;
415 let b = reg_read(regs, rs2) as i64;
416 let v = if b == 0 {
417 u64::MAX
418 } else if a == i64::MIN && b == -1 {
419 a as u64
420 } else {
421 (a / b) as u64
422 };
423 reg_write(regs, rd, v);
424 }
425 Inst::Divu { rd, rs1, rs2 } => {
426 let a = reg_read(regs, rs1);
427 let b = reg_read(regs, rs2);
428 let v = a.checked_div(b).unwrap_or(u64::MAX);
429 reg_write(regs, rd, v);
430 }
431 Inst::Rem { rd, rs1, rs2 } => {
432 let a = reg_read(regs, rs1) as i64;
433 let b = reg_read(regs, rs2) as i64;
434 let v = if b == 0 {
435 a as u64
436 } else if a == i64::MIN && b == -1 {
437 0
438 } else {
439 (a % b) as u64
440 };
441 reg_write(regs, rd, v);
442 }
443 Inst::Remu { rd, rs1, rs2 } => {
444 let a = reg_read(regs, rs1);
445 let b = reg_read(regs, rs2);
446 let v = if b == 0 { a } else { a % b };
447 reg_write(regs, rd, v);
448 }
449 Inst::Mulw { rd, rs1, rs2 } => {
450 let v = (reg_read(regs, rs1) as i32).wrapping_mul(reg_read(regs, rs2) as i32);
451 reg_write(regs, rd, v as i64 as u64);
452 }
453 Inst::Divw { rd, rs1, rs2 } => {
454 let a = reg_read(regs, rs1) as i32;
455 let b = reg_read(regs, rs2) as i32;
456 let v = if b == 0 {
457 u32::MAX as i32
458 } else if a == i32::MIN && b == -1 {
459 a
460 } else {
461 a / b
462 };
463 reg_write(regs, rd, v as i64 as u64);
464 }
465 Inst::Divuw { rd, rs1, rs2 } => {
466 let a = reg_read(regs, rs1) as u32;
467 let b = reg_read(regs, rs2) as u32;
468 let v = a.checked_div(b).unwrap_or(u32::MAX);
469 reg_write(regs, rd, v as i32 as i64 as u64);
470 }
471 Inst::Remw { rd, rs1, rs2 } => {
472 let a = reg_read(regs, rs1) as i32;
473 let b = reg_read(regs, rs2) as i32;
474 let v = if b == 0 {
475 a
476 } else if a == i32::MIN && b == -1 {
477 0
478 } else {
479 a % b
480 };
481 reg_write(regs, rd, v as i64 as u64);
482 }
483 Inst::Remuw { rd, rs1, rs2 } => {
484 let a = reg_read(regs, rs1) as u32;
485 let b = reg_read(regs, rs2) as u32;
486 let v = if b == 0 { a } else { a % b };
487 reg_write(regs, rd, v as i32 as i64 as u64);
488 }
489
490 Inst::Clz { rd, rs1 } => {
492 reg_write(regs, rd, reg_read(regs, rs1).leading_zeros() as u64);
493 }
494 Inst::Clzw { rd, rs1 } => {
495 reg_write(
496 regs,
497 rd,
498 (reg_read(regs, rs1) as u32).leading_zeros() as u64,
499 );
500 }
501 Inst::Ctz { rd, rs1 } => {
502 let v = reg_read(regs, rs1);
503 let n = if v == 0 { 64 } else { v.trailing_zeros() };
504 reg_write(regs, rd, n as u64);
505 }
506 Inst::Ctzw { rd, rs1 } => {
507 let v = reg_read(regs, rs1) as u32;
508 let n = if v == 0 { 32 } else { v.trailing_zeros() };
509 reg_write(regs, rd, n as u64);
510 }
511 Inst::Cpop { rd, rs1 } => {
512 reg_write(regs, rd, reg_read(regs, rs1).count_ones() as u64);
513 }
514 Inst::Cpopw { rd, rs1 } => {
515 reg_write(regs, rd, (reg_read(regs, rs1) as u32).count_ones() as u64);
516 }
517 Inst::SextB { rd, rs1 } => {
518 reg_write(regs, rd, reg_read(regs, rs1) as i8 as i64 as u64);
519 }
520 Inst::SextH { rd, rs1 } => {
521 reg_write(regs, rd, reg_read(regs, rs1) as i16 as i64 as u64);
522 }
523 Inst::ZextH { rd, rs1 } => {
524 reg_write(regs, rd, reg_read(regs, rs1) & 0xFFFF);
525 }
526 Inst::Rev8 { rd, rs1 } => {
527 reg_write(regs, rd, reg_read(regs, rs1).swap_bytes());
528 }
529 Inst::OrcB { rd, rs1 } => {
530 let v = reg_read(regs, rs1);
531 let mut out: u64 = 0;
533 for i in 0..8 {
534 let b = (v >> (i * 8)) & 0xFF;
535 if b != 0 {
536 out |= 0xFFu64 << (i * 8);
537 }
538 }
539 reg_write(regs, rd, out);
540 }
541 Inst::Min { rd, rs1, rs2 } => {
542 let a = reg_read(regs, rs1) as i64;
543 let b = reg_read(regs, rs2) as i64;
544 reg_write(regs, rd, a.min(b) as u64);
545 }
546 Inst::Minu { rd, rs1, rs2 } => {
547 let a = reg_read(regs, rs1);
548 let b = reg_read(regs, rs2);
549 reg_write(regs, rd, a.min(b));
550 }
551 Inst::Max { rd, rs1, rs2 } => {
552 let a = reg_read(regs, rs1) as i64;
553 let b = reg_read(regs, rs2) as i64;
554 reg_write(regs, rd, a.max(b) as u64);
555 }
556 Inst::Maxu { rd, rs1, rs2 } => {
557 let a = reg_read(regs, rs1);
558 let b = reg_read(regs, rs2);
559 reg_write(regs, rd, a.max(b));
560 }
561 Inst::Andn { rd, rs1, rs2 } => {
562 reg_write(regs, rd, reg_read(regs, rs1) & !reg_read(regs, rs2));
563 }
564 Inst::Orn { rd, rs1, rs2 } => {
565 reg_write(regs, rd, reg_read(regs, rs1) | !reg_read(regs, rs2));
566 }
567 Inst::Xnor { rd, rs1, rs2 } => {
568 reg_write(regs, rd, !(reg_read(regs, rs1) ^ reg_read(regs, rs2)));
569 }
570 Inst::Rol { rd, rs1, rs2 } => {
571 let s = reg_read(regs, rs2) as u32 & 63;
572 reg_write(regs, rd, reg_read(regs, rs1).rotate_left(s));
573 }
574 Inst::Ror { rd, rs1, rs2 } => {
575 let s = reg_read(regs, rs2) as u32 & 63;
576 reg_write(regs, rd, reg_read(regs, rs1).rotate_right(s));
577 }
578 Inst::Rolw { rd, rs1, rs2 } => {
579 let s = reg_read(regs, rs2) as u32 & 31;
580 let v = (reg_read(regs, rs1) as u32).rotate_left(s);
581 reg_write(regs, rd, v as i32 as i64 as u64);
582 }
583 Inst::Rorw { rd, rs1, rs2 } => {
584 let s = reg_read(regs, rs2) as u32 & 31;
585 let v = (reg_read(regs, rs1) as u32).rotate_right(s);
586 reg_write(regs, rd, v as i32 as i64 as u64);
587 }
588 Inst::Rori { rd, rs1, shamt } => {
589 reg_write(
590 regs,
591 rd,
592 reg_read(regs, rs1).rotate_right(shamt as u32 & 63),
593 );
594 }
595 Inst::Roriw { rd, rs1, shamt } => {
596 let v = (reg_read(regs, rs1) as u32).rotate_right(shamt as u32 & 31);
597 reg_write(regs, rd, v as i32 as i64 as u64);
598 }
599
600 Inst::Sh1add { rd, rs1, rs2 } => {
602 let v = reg_read(regs, rs1)
603 .wrapping_shl(1)
604 .wrapping_add(reg_read(regs, rs2));
605 reg_write(regs, rd, v);
606 }
607 Inst::Sh2add { rd, rs1, rs2 } => {
608 let v = reg_read(regs, rs1)
609 .wrapping_shl(2)
610 .wrapping_add(reg_read(regs, rs2));
611 reg_write(regs, rd, v);
612 }
613 Inst::Sh3add { rd, rs1, rs2 } => {
614 let v = reg_read(regs, rs1)
615 .wrapping_shl(3)
616 .wrapping_add(reg_read(regs, rs2));
617 reg_write(regs, rd, v);
618 }
619 Inst::Sh1adduw { rd, rs1, rs2 } => {
620 let a = (reg_read(regs, rs1) as u32 as u64).wrapping_shl(1);
621 reg_write(regs, rd, a.wrapping_add(reg_read(regs, rs2)));
622 }
623 Inst::Sh2adduw { rd, rs1, rs2 } => {
624 let a = (reg_read(regs, rs1) as u32 as u64).wrapping_shl(2);
625 reg_write(regs, rd, a.wrapping_add(reg_read(regs, rs2)));
626 }
627 Inst::Sh3adduw { rd, rs1, rs2 } => {
628 let a = (reg_read(regs, rs1) as u32 as u64).wrapping_shl(3);
629 reg_write(regs, rd, a.wrapping_add(reg_read(regs, rs2)));
630 }
631 Inst::Adduw { rd, rs1, rs2 } => {
632 let a = reg_read(regs, rs1) as u32 as u64;
633 reg_write(regs, rd, a.wrapping_add(reg_read(regs, rs2)));
634 }
635 Inst::Slliuw { rd, rs1, shamt } => {
636 let a = reg_read(regs, rs1) as u32 as u64;
637 reg_write(regs, rd, a.wrapping_shl(shamt as u32 & 63));
638 }
639
640 Inst::Bclr { rd, rs1, rs2 } => {
642 let bit = reg_read(regs, rs2) & 63;
643 reg_write(regs, rd, reg_read(regs, rs1) & !(1u64 << bit));
644 }
645 Inst::Bset { rd, rs1, rs2 } => {
646 let bit = reg_read(regs, rs2) & 63;
647 reg_write(regs, rd, reg_read(regs, rs1) | (1u64 << bit));
648 }
649 Inst::Binv { rd, rs1, rs2 } => {
650 let bit = reg_read(regs, rs2) & 63;
651 reg_write(regs, rd, reg_read(regs, rs1) ^ (1u64 << bit));
652 }
653 Inst::Bext { rd, rs1, rs2 } => {
654 let bit = reg_read(regs, rs2) & 63;
655 reg_write(regs, rd, (reg_read(regs, rs1) >> bit) & 1);
656 }
657 Inst::Bclri { rd, rs1, shamt } => {
658 reg_write(regs, rd, reg_read(regs, rs1) & !(1u64 << (shamt & 63)));
659 }
660 Inst::Bseti { rd, rs1, shamt } => {
661 reg_write(regs, rd, reg_read(regs, rs1) | (1u64 << (shamt & 63)));
662 }
663 Inst::Binvi { rd, rs1, shamt } => {
664 reg_write(regs, rd, reg_read(regs, rs1) ^ (1u64 << (shamt & 63)));
665 }
666 Inst::Bexti { rd, rs1, shamt } => {
667 reg_write(regs, rd, (reg_read(regs, rs1) >> (shamt & 63)) & 1);
668 }
669
670 Inst::CzeroEqz { rd, rs1, rs2 } => {
672 let v = if reg_read(regs, rs2) == 0 {
674 0
675 } else {
676 reg_read(regs, rs1)
677 };
678 reg_write(regs, rd, v);
679 }
680 Inst::CzeroNez { rd, rs1, rs2 } => {
681 let v = if reg_read(regs, rs2) != 0 {
683 0
684 } else {
685 reg_read(regs, rs1)
686 };
687 reg_write(regs, rd, v);
688 }
689
690 Inst::Lui { rd, imm } => {
692 reg_write(regs, rd, imm as i64 as u64);
693 }
694 Inst::Auipc { rd, imm } => {
697 let v = code_base.wrapping_add(pc).wrapping_add(imm as u32);
698 reg_write(regs, rd, v as i32 as i64 as u64);
699 }
700
701 Inst::Jal { rd, imm } => {
703 if rd != 0 {
704 reg_write(regs, rd, code_base.wrapping_add(next_pc) as u64);
706 }
707 let target = (pc as i64).wrapping_add(imm as i64) as u32;
708 next_idx_override = Some(match find_idx_for_pc(insts, target) {
714 Some(i) if insts[i].is_gas_block_start => i,
715 _ => {
716 regs.pc = pc as u64;
717 return ExitReason::Panic;
718 }
719 });
720 }
721 Inst::Jalr { rd, rs1, imm } => {
727 let target_va = (reg_read(regs, rs1) as u32).wrapping_add(imm as u32);
728 if rd != 0 {
729 reg_write(regs, rd, code_base.wrapping_add(next_pc) as u64);
730 }
731 let target_off = target_va.wrapping_sub(code_base);
732 next_idx_override = Some(match find_idx_for_pc(insts, target_off) {
733 Some(i) if insts[i].is_gas_block_start => i,
734 _ => {
735 regs.pc = pc as u64;
736 return ExitReason::Panic;
737 }
738 });
739 }
740 Inst::Beq { rs1, rs2, imm } => {
741 if reg_read(regs, rs1) == reg_read(regs, rs2) {
742 let target = (pc as i64).wrapping_add(imm as i64) as u32;
743 match find_idx_for_pc(insts, target) {
744 Some(i) if insts[i].is_gas_block_start => next_idx_override = Some(i),
745 _ => {
746 regs.pc = pc as u64;
747 return ExitReason::Panic;
748 }
749 }
750 }
751 }
752 Inst::Bne { rs1, rs2, imm } => {
753 if reg_read(regs, rs1) != reg_read(regs, rs2) {
754 let target = (pc as i64).wrapping_add(imm as i64) as u32;
755 match find_idx_for_pc(insts, target) {
756 Some(i) if insts[i].is_gas_block_start => next_idx_override = Some(i),
757 _ => {
758 regs.pc = pc as u64;
759 return ExitReason::Panic;
760 }
761 }
762 }
763 }
764 Inst::Blt { rs1, rs2, imm } => {
765 if (reg_read(regs, rs1) as i64) < (reg_read(regs, rs2) as i64) {
766 let target = (pc as i64).wrapping_add(imm as i64) as u32;
767 match find_idx_for_pc(insts, target) {
768 Some(i) if insts[i].is_gas_block_start => next_idx_override = Some(i),
769 _ => {
770 regs.pc = pc as u64;
771 return ExitReason::Panic;
772 }
773 }
774 }
775 }
776 Inst::Bge { rs1, rs2, imm } => {
777 if (reg_read(regs, rs1) as i64) >= (reg_read(regs, rs2) as i64) {
778 let target = (pc as i64).wrapping_add(imm as i64) as u32;
779 match find_idx_for_pc(insts, target) {
780 Some(i) if insts[i].is_gas_block_start => next_idx_override = Some(i),
781 _ => {
782 regs.pc = pc as u64;
783 return ExitReason::Panic;
784 }
785 }
786 }
787 }
788 Inst::Bltu { rs1, rs2, imm } => {
789 if reg_read(regs, rs1) < reg_read(regs, rs2) {
790 let target = (pc as i64).wrapping_add(imm as i64) as u32;
791 match find_idx_for_pc(insts, target) {
792 Some(i) if insts[i].is_gas_block_start => next_idx_override = Some(i),
793 _ => {
794 regs.pc = pc as u64;
795 return ExitReason::Panic;
796 }
797 }
798 }
799 }
800 Inst::Bgeu { rs1, rs2, imm } => {
801 if reg_read(regs, rs1) >= reg_read(regs, rs2) {
802 let target = (pc as i64).wrapping_add(imm as i64) as u32;
803 match find_idx_for_pc(insts, target) {
804 Some(i) if insts[i].is_gas_block_start => next_idx_override = Some(i),
805 _ => {
806 regs.pc = pc as u64;
807 return ExitReason::Panic;
808 }
809 }
810 }
811 }
812
813 Inst::Fence | Inst::FenceI => {}
815
816 Inst::Trap => {
818 regs.pc = pc as u64;
819 return ExitReason::Trap;
820 }
821 Inst::EcallJar => {
822 let cost = crate::gas_const::ecall_dynamic_cost(false);
827 if gas.remaining() < cost {
828 regs.pc = pc as u64;
829 return ExitReason::OutOfGas;
830 }
831 gas.charge(cost).expect("ecall cost checked");
832 regs.pc = next_pc as u64;
833 match handler.handle(EcallKind::Ecall, regs, mem) {
834 EcallResult::Continue => match find_idx_for_pc(insts, next_pc) {
835 Some(i) => next_idx_override = Some(i),
836 None => return ExitReason::Panic,
837 },
838 EcallResult::Exit(r) => return r,
839 }
840 }
841 Inst::Ecalli { imm } => {
842 let cost = crate::gas_const::ecall_dynamic_cost(true);
843 if gas.remaining() < cost {
844 regs.pc = pc as u64;
845 return ExitReason::OutOfGas;
846 }
847 gas.charge(cost).expect("ecall cost checked");
848 regs.pc = next_pc as u64;
849 match handler.handle(EcallKind::Ecalli(imm as u32), regs, mem) {
850 EcallResult::Continue => match find_idx_for_pc(insts, next_pc) {
851 Some(i) => next_idx_override = Some(i),
852 None => return ExitReason::Panic,
853 },
854 EcallResult::Exit(r) => return r,
855 }
856 }
857 Inst::Fallthrough => {
858 }
862
863 Inst::Reserved { .. } => {
864 regs.pc = pc as u64;
865 return ExitReason::Panic;
866 }
867 }
868
869 match next_idx_override {
873 Some(new_idx) => idx = new_idx,
874 None => {
875 idx += 1;
876 if idx >= insts.len() {
877 regs.pc = next_pc as u64;
880 return ExitReason::Panic;
881 }
882 }
883 }
884 }
885 }
886}
887
888#[inline]
897fn reg_read(regs: &Regs, x: u8) -> u64 {
898 match crate::regs::REG_SLOT_LUT[(x & 31) as usize] {
899 0xFF => 0,
900 s => regs.gpr[s as usize],
901 }
902}
903
904#[inline]
908fn reg_write(regs: &mut Regs, x: u8, v: u64) {
909 let s = crate::regs::REG_SLOT_LUT[(x & 31) as usize];
910 if s != 0xFF {
911 regs.gpr[s as usize] = v;
912 }
913}
914
915#[inline]
918fn compute_addr(regs: &Regs, rs1: u8, imm: i32) -> u32 {
919 (reg_read(regs, rs1) as u32).wrapping_add(imm as u32)
920}
921
922#[inline]
930fn read_code(code: &[u8], code_base: u32, addr: u32, width: usize) -> Option<u64> {
931 let off = addr.checked_sub(code_base)? as usize;
932 let end = off.checked_add(width)?;
933 let rounded = (code.len() as u32).next_multiple_of(crate::mem::PAGE_SIZE) as usize;
938 if end > rounded {
939 return None;
940 }
941 let mut buf = [0u8; 8];
942 for (k, b) in buf.iter_mut().enumerate().take(width) {
943 let o = off + k;
944 if o < code.len() {
945 *b = code[o];
946 }
947 }
948 Some(u64::from_le_bytes(buf))
949}
950
951#[inline]
955fn load_u8<M: Memory>(mem: &M, code: &[u8], code_base: u32, addr: u32) -> Option<u8> {
956 mem.read_u8(addr)
957 .or_else(|| read_code(code, code_base, addr, 1).map(|v| v as u8))
958}
959#[inline]
960fn load_u16<M: Memory>(mem: &M, code: &[u8], code_base: u32, addr: u32) -> Option<u16> {
961 mem.read_u16_le(addr)
962 .or_else(|| read_code(code, code_base, addr, 2).map(|v| v as u16))
963}
964#[inline]
965fn load_u32<M: Memory>(mem: &M, code: &[u8], code_base: u32, addr: u32) -> Option<u32> {
966 mem.read_u32_le(addr)
967 .or_else(|| read_code(code, code_base, addr, 4).map(|v| v as u32))
968}
969#[inline]
970fn load_u64<M: Memory>(mem: &M, code: &[u8], code_base: u32, addr: u32) -> Option<u64> {
971 mem.read_u64_le(addr)
972 .or_else(|| read_code(code, code_base, addr, 8))
973}
974
975#[inline]
984fn store_writable<M: Memory>(mem: &M, addr: u32, width: u32) -> bool {
985 mem.perm_of(addr) == perm::RW && mem.perm_of(addr.wrapping_add(width - 1)) == perm::RW
986}
987
988#[inline]
990fn page_fault(regs: &mut Regs, pc: u32, addr: u32) -> ExitReason {
991 regs.pc = pc as u64;
992 ExitReason::PageFault(addr & !0xFFF)
993}
994
995#[inline]
997fn find_idx_for_pc(insts: &[RvPreDecodedInst], pc: u32) -> Option<usize> {
998 insts.binary_search_by_key(&pc, |i| i.pc).ok()
999}
1000
1001#[cfg(test)]
1002#[allow(clippy::identity_op)] mod tests {
1004 use super::*;
1005 use crate::ecall::PanickingHandler;
1006 use crate::mem::CopyingMemory;
1007 use crate::predecode::predecode;
1008 use alloc::vec::Vec;
1009
1010 fn enc4(words: &[u32]) -> Vec<u8> {
1011 let mut v = Vec::with_capacity(words.len() * 4);
1012 for w in words {
1013 v.extend_from_slice(&w.to_le_bytes());
1014 }
1015 v
1016 }
1017
1018 fn run_simple(code: &[u8], initial_gas: u64) -> (Regs, ExitReason, u64) {
1019 let pre = predecode(code);
1020 let mut regs = Regs::new();
1021 let mut mem = CopyingMemory::new();
1022 let mut gas = GasCounter::new(initial_gas);
1023 let mut h = PanickingHandler;
1024 let reason = Interpreter::run(&pre, code, 0, &mut regs, &mut mem, &mut gas, &mut h);
1025 let used = initial_gas.saturating_sub(gas.remaining());
1026 (regs, reason, used)
1027 }
1028
1029 #[test]
1030 fn trap_immediately() {
1031 let code = enc4(&[0x0000_000B]);
1034 let (regs, reason, _) = run_simple(&code, 1_000_000);
1035 assert_eq!(reason, ExitReason::Trap);
1036 assert_eq!(regs.pc, 0);
1037 }
1038
1039 #[test]
1040 fn addi_then_trap() {
1041 let addi = (42u32 << 20) | (10 << 7) | 0x13;
1046 let trap = 0x0000_000Bu32;
1047 let code = enc4(&[addi, trap]);
1048 let (regs, reason, _) = run_simple(&code, 1_000_000);
1049 assert_eq!(reason, ExitReason::Trap);
1050 assert_eq!(regs.gpr[7], 42);
1052 }
1053
1054 #[test]
1055 fn div_by_zero_returns_neg_one() {
1056 let addi_x5_7 = (7u32 << 20) | (5 << 7) | 0x13;
1058 let addi_x6_0 = (0u32 << 20) | (6 << 7) | 0x13;
1059 let div = (1u32 << 25) | (6 << 20) | (5 << 15) | (0b100 << 12) | (7 << 7) | 0x33;
1061 let trap = 0x0000_000Bu32;
1062 let code = enc4(&[addi_x5_7, addi_x6_0, div, trap]);
1063 let (regs, _reason, _) = run_simple(&code, 1_000_000);
1064 assert_eq!(regs.gpr[4], u64::MAX);
1066 }
1067
1068 #[test]
1069 fn out_of_gas_at_block_start() {
1070 let addi = (1u32 << 20) | (10 << 7) | 0x13;
1072 let trap = 0x0000_000Bu32;
1073 let code = enc4(&[addi, trap]);
1074 let (regs, reason, _) = run_simple(&code, 0);
1075 assert_eq!(reason, ExitReason::OutOfGas);
1076 assert_eq!(regs.pc, 0);
1077 }
1078
1079 #[test]
1080 fn sign_extend_addiw() {
1081 let addiw = ((-1i32) as u32) << 20 | (0 << 15) | (0 << 12) | (10 << 7) | 0x1B;
1083 let trap = 0x0000_000Bu32;
1084 let code = enc4(&[addiw, trap]);
1085 let (regs, _reason, _) = run_simple(&code, 1_000_000);
1086 assert_eq!(regs.gpr[7], u64::MAX);
1087 }
1088
1089 #[test]
1090 fn czero_eqz_zeroes_when_rs2_is_zero() {
1091 let addi_x5 = (42u32 << 20) | (5 << 7) | 0x13;
1094 let addi_x6 = (0u32 << 20) | (6 << 7) | 0x13;
1095 let czero = (0b0000111u32 << 25) | (6 << 20) | (5 << 15) | (0b101 << 12) | (7 << 7) | 0x33;
1096 let trap = 0x0000_000Bu32;
1097 let code = enc4(&[addi_x5, addi_x6, czero, trap]);
1098 let (regs, _reason, _) = run_simple(&code, 1_000_000);
1099 assert_eq!(regs.gpr[4], 0); }
1101
1102 #[test]
1103 fn czero_eqz_passes_when_rs2_nonzero() {
1104 let addi_x5 = (42u32 << 20) | (5 << 7) | 0x13;
1105 let addi_x6 = (3u32 << 20) | (6 << 7) | 0x13;
1106 let czero = (0b0000111u32 << 25) | (6 << 20) | (5 << 15) | (0b101 << 12) | (7 << 7) | 0x33;
1107 let trap = 0x0000_000Bu32;
1108 let code = enc4(&[addi_x5, addi_x6, czero, trap]);
1109 let (regs, _reason, _) = run_simple(&code, 1_000_000);
1110 assert_eq!(regs.gpr[4], 42); }
1112
1113 #[test]
1114 fn reserved_custom0_011_panics() {
1115 let word = (0u32 << 20) | (5 << 15) | (0b011 << 12) | (0 << 7) | (0b00010 << 2) | 0b11;
1118 let code = enc4(&[word]);
1119 let pre = predecode(&code);
1120 let mut regs = Regs::new();
1121 let mut mem = CopyingMemory::new();
1122 let mut gas = GasCounter::new(1_000_000);
1123 let mut h = PanickingHandler;
1124 let reason = Interpreter::run(&pre, &code, 0, &mut regs, &mut mem, &mut gas, &mut h);
1125 assert_eq!(reason, ExitReason::Panic);
1126 }
1127
1128 #[test]
1139 fn branch_to_non_block_start_panics() {
1140 let beq = 0x0000_0463u32; let addi1 = (1u32 << 20) | (10 << 7) | 0x13;
1146 let addi2 = (2u32 << 20) | (11 << 7) | 0x13;
1147 let trap = 0x0000_000Bu32;
1148 let code = enc4(&[beq, addi1, addi2, trap]);
1149 let (regs, reason, _) = run_simple(&code, 1_000_000);
1150 assert_eq!(reason, ExitReason::Panic);
1151 assert_eq!(regs.pc, 0); }
1153
1154 #[test]
1155 fn jal_to_non_block_start_panics() {
1156 let jal = 0x0080_006Fu32; let addi1 = (1u32 << 20) | (10 << 7) | 0x13;
1162 let addi2 = (2u32 << 20) | (11 << 7) | 0x13;
1163 let trap = 0x0000_000Bu32;
1164 let code = enc4(&[jal, addi1, addi2, trap]);
1165 let (regs, reason, _) = run_simple(&code, 1_000_000);
1166 assert_eq!(reason, ExitReason::Panic);
1167 assert_eq!(regs.pc, 0);
1168 }
1169
1170 #[test]
1171 fn branch_to_real_block_start_is_allowed() {
1172 let beq = 0x0000_0463u32; let trap = 0x0000_000Bu32;
1179 let addi = (7u32 << 20) | (10 << 7) | 0x13;
1180 let code = enc4(&[beq, trap, addi, trap]);
1181 let (regs, reason, _) = run_simple(&code, 1_000_000);
1182 assert_eq!(reason, ExitReason::Trap);
1183 assert_eq!(regs.gpr[7], 7); }
1185
1186 #[test]
1189 fn auipc_load_reads_own_code_region() {
1190 let auipc = (0u32 << 12) | (10 << 7) | 0x17; let lw = (0u32 << 20) | (10 << 15) | (0b010 << 12) | (11 << 7) | 0x03; let trap = 0x0000_000Bu32;
1197 let code = enc4(&[auipc, lw, trap]);
1198 let pre = predecode(&code);
1199 let mut regs = Regs::new();
1200 let mut mem = CopyingMemory::new();
1201 mem.base = 0x1000_0000; let mut gas = GasCounter::new(1_000_000);
1203 let mut h = PanickingHandler;
1204 let code_base = 0x0040_0000u32;
1205 let reason = Interpreter::run(
1206 &pre, &code, code_base, &mut regs, &mut mem, &mut gas, &mut h,
1207 );
1208 assert_eq!(reason, ExitReason::Trap);
1209 assert_eq!(regs.gpr[7], code_base as u64); assert_eq!(regs.gpr[8] as u32, auipc); }
1212
1213 #[test]
1214 fn store_into_code_region_faults() {
1215 let auipc = (0u32 << 12) | (10 << 7) | 0x17; let sw = (0u32 << 25) | (0 << 20) | (10 << 15) | (0b010 << 12) | (0 << 7) | 0x23; let trap = 0x0000_000Bu32;
1220 let code = enc4(&[auipc, sw, trap]);
1221 let pre = predecode(&code);
1222 let mut regs = Regs::new();
1223 let mut mem = CopyingMemory::new();
1224 mem.base = 0x1000_0000;
1225 let mut gas = GasCounter::new(1_000_000);
1226 let mut h = PanickingHandler;
1227 let code_base = 0x0040_0000u32;
1228 let reason = Interpreter::run(
1229 &pre, &code, code_base, &mut regs, &mut mem, &mut gas, &mut h,
1230 );
1231 assert_eq!(reason, ExitReason::PageFault(code_base));
1232 }
1233
1234 #[test]
1237 fn store_writable_respects_per_page_perms() {
1238 let page = crate::mem::PAGE_SIZE;
1242 let mut mem = CopyingMemory::with_pages(2, perm::RW);
1243 mem.perms[1] = perm::RO;
1244 assert!(store_writable(&mem, 0, 4)); assert!(!store_writable(&mem, page, 4)); assert!(!store_writable(&mem, page - 2, 4)); }
1248
1249 #[test]
1250 fn guest_store_to_ro_page_faults() {
1251 let lui = (1u32 << 12) | (5 << 7) | 0x37; let sw = (0u32 << 25) | (0 << 20) | (5 << 15) | (0b010 << 12) | (0 << 7) | 0x23; let trap = 0x0000_000Bu32;
1257 let code = enc4(&[lui, sw, trap]);
1258 let pre = predecode(&code);
1259 let mut regs = Regs::new();
1260 let mut mem = CopyingMemory::with_pages(2, perm::RW);
1261 mem.perms[1] = perm::RO;
1262 let mut gas = GasCounter::new(1_000_000);
1263 let mut h = PanickingHandler;
1264 let reason = Interpreter::run(&pre, &code, 0, &mut regs, &mut mem, &mut gas, &mut h);
1265 assert_eq!(reason, ExitReason::PageFault(crate::mem::PAGE_SIZE));
1266 assert_eq!(mem.read_u32_le(crate::mem::PAGE_SIZE), Some(0));
1268 }
1269
1270 #[test]
1273 fn entry_at_non_block_start_panics() {
1274 let addi1 = (1u32 << 20) | (10 << 7) | 0x13;
1279 let addi2 = (2u32 << 20) | (11 << 7) | 0x13;
1280 let trap = 0x0000_000Bu32;
1281 let code = enc4(&[addi1, addi2, trap]);
1282 let pre = predecode(&code);
1283 let mut regs = Regs::new();
1284 regs.pc = 4; let mut mem = CopyingMemory::new();
1286 let mut gas = GasCounter::new(1_000_000);
1287 let mut h = PanickingHandler;
1288 let reason = Interpreter::run(&pre, &code, 0, &mut regs, &mut mem, &mut gas, &mut h);
1289 assert_eq!(reason, ExitReason::Panic);
1290 }
1291
1292 #[test]
1293 fn entry_at_real_block_start_is_allowed() {
1294 let trap = 0x0000_000Bu32;
1297 let addi = (7u32 << 20) | (10 << 7) | 0x13;
1298 let code = enc4(&[trap, addi, trap]);
1299 let pre = predecode(&code);
1300 let mut regs = Regs::new();
1301 regs.pc = 4; let mut mem = CopyingMemory::new();
1303 let mut gas = GasCounter::new(1_000_000);
1304 let mut h = PanickingHandler;
1305 let reason = Interpreter::run(&pre, &code, 0, &mut regs, &mut mem, &mut gas, &mut h);
1306 assert_eq!(reason, ExitReason::Trap);
1307 assert_eq!(regs.gpr[7], 7); }
1309
1310 #[test]
1313 fn x3_x4_execute_as_real_registers() {
1314 let addi_x3_7 = (7u32 << 20) | (3 << 7) | 0x13; let addi_x4_5 = (5u32 << 20) | (4 << 7) | 0x13; let add_x5 = (4u32 << 20) | (3 << 15) | (5 << 7) | 0x33; let trap = 0x0000_000Bu32;
1321 let code = enc4(&[addi_x3_7, addi_x4_5, add_x5, trap]);
1322 let (regs, reason, _) = run_simple(&code, 1_000_000);
1323 assert_eq!(reason, ExitReason::Trap);
1324 assert_eq!(regs.gpr[2], 12);
1326 assert_eq!(regs.gpr[13], 7);
1327 assert_eq!(regs.gpr[14], 5);
1328 }
1329
1330 #[test]
1331 fn x3_free_arithmetic_still_runs() {
1332 let add_ok = 0x0073_02B3u32; let trap = 0x0000_000Bu32;
1335 let code = enc4(&[add_ok, trap]);
1336 let (_regs, reason, _) = run_simple(&code, 1_000_000);
1337 assert_eq!(reason, ExitReason::Trap);
1338 }
1339}