diff --git a/rvgo/fast/vm.go b/rvgo/fast/vm.go index 9036f03b..1e9c5887 100644 --- a/rvgo/fast/vm.go +++ b/rvgo/fast/vm.go @@ -682,8 +682,16 @@ func (inst *InstrumentedState) riscvStep() (outErr error) { case 0: // 000 = ADDIW rdValue = mask32Signed64(add64(rs1Value, imm)) case 1: // 001 = SLLIW + // SLLIW where imm[5] != 0 is reserved + if and64(imm, toU64(0x20)) != 0 { + revertWithCode(riscv.ErrInvalidSyscall, fmt.Errorf("illegal instruction %d: reserved instruction encoding", instr)) + } rdValue = mask32Signed64(shl64(and64(imm, toU64(0x1F)), rs1Value)) case 5: // 101 = SR~ + // SRLIW and SRAIW where imm[5] != 0 is reserved + if and64(imm, toU64(0x20)) != 0 { + revertWithCode(riscv.ErrInvalidSyscall, fmt.Errorf("illegal instruction %d: reserved instruction encoding", instr)) + } shamt := and64(imm, toU64(0x1F)) switch shr64(toU64(5), imm) { // top 7 bits select the shift type case 0x00: // 0000000 = SRLIW diff --git a/rvgo/slow/vm.go b/rvgo/slow/vm.go index 99b40192..0d934471 100644 --- a/rvgo/slow/vm.go +++ b/rvgo/slow/vm.go @@ -866,8 +866,16 @@ func Step(calldata []byte, po PreimageOracle) (stateHash common.Hash, outErr err case 0: // 000 = ADDIW rdValue = mask32Signed64(add64(rs1Value, imm)) case 1: // 001 = SLLIW + // SLLIW where imm[5] != 0 is reserved + if and64(imm, toU64(0x20)) != (U64{}) { + revertWithCode(riscv.ErrInvalidSyscall, fmt.Errorf("illegal instruction %d: reserved instruction encoding", instr)) + } rdValue = mask32Signed64(shl64(and64(imm, toU64(0x1F)), rs1Value)) case 5: // 101 = SR~ + // SRLIW and SRAIW imm[5] != 0 is reserved + if and64(imm, toU64(0x20)) != (U64{}) { + revertWithCode(riscv.ErrInvalidSyscall, fmt.Errorf("illegal instruction %d: reserved instruction encoding", instr)) + } shamt := and64(imm, toU64(0x1F)) switch shr64(toU64(5), imm).val() { // top 7 bits select the shift type case 0x00: // 0000000 = SRLIW diff --git a/rvsol/src/RISCV.sol b/rvsol/src/RISCV.sol index 5fb7f096..c25cf77f 100644 --- a/rvsol/src/RISCV.sol +++ b/rvsol/src/RISCV.sol @@ -1291,9 +1291,15 @@ contract RISCV is IBigStepper { } case 1 { // 001 = SLLIW + + // SLLIW where imm[5] != 0 is reserved + if and64(imm, toU64(0x20)) { revertWithCode(0xf001ca11) } rdValue := mask32Signed64(shl64(and64(imm, toU64(0x1F)), rs1Value)) } case 5 { + // SRLIW and SRAIW where imm[5] != 0 is reserved + if and64(imm, toU64(0x20)) { revertWithCode(0xf001ca11) } + // 101 = SR~ let shamt := and64(imm, toU64(0x1F)) switch shr64(toU64(5), imm) diff --git a/rvsol/test/RISCV.t.sol b/rvsol/test/RISCV.t.sol index 644d62d8..700e5d51 100644 --- a/rvsol/test/RISCV.t.sol +++ b/rvsol/test/RISCV.t.sol @@ -2479,6 +2479,18 @@ contract RISCV_Test is CommonTest { riscv.step(encodedState, proof, 0); } + function test_revert_reserved_slliw_instruction() public { + uint16 shamt = 0x15; + uint16 imm = (0 << 7) | shamt | 0x20; // set 0x20 to make imm[5] != 0 + uint32 insn = encodeIType(0x1b, 17, 1, 25, imm); // slliw x17, x25, 0x15 + (State memory state, bytes memory proof) = constructRISCVState(0, insn); + state.registers[25] = 0xf956; + bytes memory encodedState = encodeState(state); + + vm.expectRevert(hex"00000000000000000000000000000000000000000000000000000000f001ca11"); + riscv.step(encodedState, proof, 0); + } + function test_reserved_load_instruction() public { bytes32 value = hex"61fb11d66dcc9d48"; uint16 offset = 0x6bf; @@ -2486,6 +2498,7 @@ contract RISCV_Test is CommonTest { uint32 insn = encodeIType(0x3, 21, 0x7, 4, offset); // lhu x21, funct 0x7, offset(x4) (State memory state, bytes memory proof) = constructRISCVState(0, insn, addr, value); state.registers[4] = 0xd34d; + bytes memory encodedState = encodeState(state); vm.expectRevert(hex"00000000000000000000000000000000000000000000000000000000f001ca11");