Commit b8921436 authored by smartcontracts's avatar smartcontracts Committed by Adrian Sutton

fix: correctly verify mips instruction encoding (#237)

A lot of instructions in the MIPS spec require that certain fields
be set to zero. Most of the time this isn't actually a problem but
this can cause side-effects in a few cases. A buggy compiler could
create an issue if it ever spit out non-compliant instructions.
This PR implements those zero value enforcement checks for all
instructions that we implement.
parent db61d2bb
...@@ -78,6 +78,9 @@ func ExecMipsCoreStepLogic(cpu *mipsevm.CpuScalars, registers *[32]uint32, memor ...@@ -78,6 +78,9 @@ func ExecMipsCoreStepLogic(cpu *mipsevm.CpuScalars, registers *[32]uint32, memor
} }
} }
// Verify that the instruction is properly encoded.
CheckZeroEncoding(insn)
// ALU // ALU
val := ExecuteMipsInstruction(insn, opcode, fun, rs, rt, mem) val := ExecuteMipsInstruction(insn, opcode, fun, rs, rt, mem)
...@@ -120,6 +123,56 @@ func ExecMipsCoreStepLogic(cpu *mipsevm.CpuScalars, registers *[32]uint32, memor ...@@ -120,6 +123,56 @@ func ExecMipsCoreStepLogic(cpu *mipsevm.CpuScalars, registers *[32]uint32, memor
return HandleRd(cpu, registers, rdReg, val, true) return HandleRd(cpu, registers, rdReg, val, true)
} }
func CheckZeroEncoding(insn uint32) {
// Pick out the opcode and function code.
opcode := uint8(insn >> 26)
funcCode := uint8(insn & 0x3F)
// Pick out the registers.
rs := uint8((insn >> 21) & 0x1F)
rt := uint8((insn >> 16) & 0x1F)
rd := uint8((insn >> 11) & 0x1F)
shamt := uint8((insn >> 6) & 0x1F)
// Checks for R-type instructions.
if opcode == 0x00 {
// Check for zero rs.
if funcCode == 0x00 || funcCode == 0x02 || funcCode == 0x03 || funcCode == 0x10 || funcCode == 0x12 {
if rs != 0 {
panic("rs not zero")
}
}
// Check for zero rt.
if funcCode == 0x08 || funcCode == 0x09 || (funcCode >= 0x10 && funcCode <= 0x13) {
if rt != 0 {
panic("rt not zero")
}
}
// Check for zero rd.
if funcCode == 0x08 || funcCode == 0x11 || funcCode == 0x13 || (funcCode >= 0x18 && funcCode <= 0x1B) {
if rd != 0 {
panic("rd not zero")
}
}
// Check for zero shamt.
if funcCode == 0x08 || funcCode == 0x09 || funcCode == 0x0F || (funcCode >= 0x10 && funcCode <= 0x13) || (funcCode >= 0x18 && funcCode <= 0x1B) || (funcCode >= 0x20 && funcCode <= 0x27) || funcCode == 0x2A || funcCode == 0x2B {
if shamt != 0 {
panic("shamt not zero")
}
}
}
// Check for zero rs in LUI.
if opcode == 0x0F {
if rs != 0 {
panic("rs not zero")
}
}
}
func ExecuteMipsInstruction(insn, opcode, fun, rs, rt, mem uint32) uint32 { func ExecuteMipsInstruction(insn, opcode, fun, rs, rt, mem uint32) uint32 {
if opcode == 0 || (opcode >= 8 && opcode < 0xF) { if opcode == 0 || (opcode >= 8 && opcode < 0xF) {
// transform ArithLogI to SPECIAL // transform ArithLogI to SPECIAL
......
...@@ -103,6 +103,8 @@ func TestEVM(t *testing.T) { ...@@ -103,6 +103,8 @@ func TestEVM(t *testing.T) {
require.NotEqual(t, uint32(testutil.EndAddr), goState.GetState().GetPC(), "must not reach end") require.NotEqual(t, uint32(testutil.EndAddr), goState.GetState().GetPC(), "must not reach end")
require.True(t, goState.GetState().GetExited(), "must set exited state") require.True(t, goState.GetState().GetExited(), "must set exited state")
require.Equal(t, uint8(1), goState.GetState().GetExitCode(), "must exit with 1") require.Equal(t, uint8(1), goState.GetState().GetExitCode(), "must exit with 1")
} else if expectPanic {
require.NotEqual(t, uint32(testutil.EndAddr), state.Cpu.PC, "must not reach end")
} else { } else {
require.Equal(t, uint32(testutil.EndAddr), state.Cpu.PC, "must reach end") require.Equal(t, uint32(testutil.EndAddr), state.Cpu.PC, "must reach end")
// inspect test result // inspect test result
......
# Utility for generating assembly test files for the MIPS instructions that panic when specific
# fields in the encoded instruction are nonzero. Using a script to do this is much less prone to
# human error than writing these tests by hand.
import os
# Format is (opcode, funct, shamt, rd, rt, rs, field_to_make_nonzero)
tests = {
'ADD': [('000000', '100000', '00001', '01011', '01010', '01001', 'shamt')], # SHAMT nonzero
'ADDU': [('000000', '100001', '00001', '01011', '01010', '01001', 'shamt')], # SHAMT nonzero
'AND': [('000000', '100100', '00001', '01011', '01010', '01001', 'shamt')], # SHAMT nonzero
'DIV': [
('000000', '011010', '00001', '01010', '00000', '01001', 'rd'), # RD nonzero
('000000', '011010', '00001', '00000', '01010', '01001', 'shamt'), # SHAMT nonzero
],
'DIVU': [
('000000', '011011', '00001', '01010', '00000', '01001', 'rd'), # RD nonzero
('000000', '011011', '00001', '00000', '01010', '01001', 'shamt'), # SHAMT nonzero
],
'JALR': [
('000000', '001001', '00000', '01011', '01001', '01010', 'rt'), # RT nonzero
('000000', '001001', '00001', '01011', '01001', '00000', 'shamt'), # SHAMT nonzero
],
'JR': [
('000000', '001000', '00000', '01011', '01001', '00000', 'rd'), # RD nonzero
('000000', '001000', '00000', '00000', '01001', '01010', 'rt'), # RT nonzero
('000000', '001000', '00001', '00000', '01001', '00000', 'shamt'), # SHAMT nonzero
],
'LUI': [('001111', '00000', '01010', '00000', '00000', '01001', 'rs')], # RS nonzero
'MFHI': [
('000000', '010000', '00000', '01011', '01010', '00000', 'rt'), # RT nonzero
('000000', '010000', '00001', '01011', '00000', '00000', 'shamt'), # SHAMT nonzero
('000000', '010000', '00000', '01011', '00000', '01001', 'rs'), # RS nonzero
],
'MFLO': [
('000000', '010010', '00000', '01011', '01010', '00000', 'rt'), # RT nonzero
('000000', '010010', '00001', '01011', '00000', '00000', 'shamt'), # SHAMT nonzero
('000000', '010010', '00000', '01011', '00000', '01001', 'rs'), # RS nonzero
],
'MTHI': [
('000000', '010001', '00000', '01011', '01010', '00000', 'rd'), # RD nonzero
('000000', '010001', '00000', '01001', '01010', '00000', 'rt'), # RT nonzero
('000000', '010001', '00001', '01001', '00000', '00000', 'shamt'), # SHAMT nonzero
],
'MTLO': [
('000000', '010011', '00000', '01011', '01010', '00000', 'rd'), # RD nonzero
('000000', '010011', '00000', '01001', '01010', '00000', 'rt'), # RT nonzero
('000000', '010011', '00001', '01001', '00000', '00000', 'shamt'), # SHAMT nonzero
],
'MULT': [
('000000', '011000', '00000', '01011', '01010', '00000', 'rd'), # RD nonzero
('000000', '011000', '00001', '00000', '01010', '01001', 'shamt'), # SHAMT nonzero
],
'MULTU': [
('000000', '011001', '00000', '01011', '01010', '00000', 'rd'), # RD nonzero
('000000', '011001', '00001', '00000', '01010', '01001', 'shamt'), # SHAMT nonzero
],
'NOR': [('000000', '100111', '00001', '01011', '01010', '01001', 'shamt')], # SHAMT nonzero
'OR': [('000000', '100101', '00001', '01011', '01010', '01001', 'shamt')], # SHAMT nonzero
'SLL': [('000000', '000000', '00001', '01011', '01010', '01001', 'shamt')], # SHAMT nonzero
'SLT': [('000000', '101010', '00001', '01011', '01010', '01001', 'shamt')], # SHAMT nonzero
'SLTU': [('000000', '101011', '00001', '01011', '01010', '01001', 'shamt')], # SHAMT nonzero
'SRA': [
('000000', '000011', '00001', '01011', '01010', '01001', 'shamt'), # SHAMT nonzero
('000000', '000011', '00000', '01011', '01010', '01001', 'rs'), # RS nonzero
],
'SRL': [
('000000', '000010', '00001', '01011', '01010', '01001', 'shamt'), # SHAMT nonzero
('000000', '000010', '00000', '01011', '01010', '01001', 'rs'), # RS nonzero
],
'SUB': [('000000', '100010', '00001', '01011', '01010', '01001', 'shamt')], # SHAMT nonzero
'SUBU': [('000000', '100011', '00001', '01011', '01010', '01001', 'shamt')], # SHAMT nonzero
'SYNC': [('000000', '001111', '00001', '00000', '00000', '00000', 'shamt')], # SHAMT nonzero
'XOR': [('000000', '100110', '00001', '01011', '01010', '01001', 'shamt')], # SHAMT nonzero
}
def pad_to_length(binary_str, length):
return binary_str.zfill(length)
def generate_instruction(opcode, rs, rt, rd, shamt, funct):
binary_instruction = (
pad_to_length(opcode, 6) +
pad_to_length(rs, 5) +
pad_to_length(rt, 5) +
pad_to_length(rd, 5) +
pad_to_length(shamt, 5) +
pad_to_length(funct, 6)
)
hex_instruction = hex(int(binary_instruction, 2))[2:].zfill(8)
return '0x' + hex_instruction
def create_test_file(instruction, field, hex_instruction):
return f"""###############################################################################
# Description:
# Tests that the '{instruction.lower()}' instruction panics when the {field} field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid {instruction} (nonzero {field} field)
.word {hex_instruction}
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
"""
def write_test_file(filename, content):
os.makedirs('./test', exist_ok=True)
with open(f'./test/{filename}', 'w') as file:
file.write(content)
for instr, cases in tests.items():
for params in cases:
opcode, funct, shamt, rd, rt, rs, field = params
hex_instr = generate_instruction(opcode, rs, rt, rd, shamt, funct)
test_content = create_test_file(instr, field, hex_instr)
filename = f"{instr.lower()}_nonzero_{field}_panic.asm"
write_test_file(filename, test_content)
###############################################################################
# Description:
# Tests that the 'add' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid ADD (nonzero shamt field)
.word 0x012a5860
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'addu' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid ADDU (nonzero shamt field)
.word 0x012a5861
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'and' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid AND (nonzero shamt field)
.word 0x012a5864
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'div' instruction panics when the rd field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid DIV (nonzero rd field)
.word 0x0120505a
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'div' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid DIV (nonzero shamt field)
.word 0x012a005a
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'divu' instruction panics when the rd field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid DIVU (nonzero rd field)
.word 0x0120505b
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'divu' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid DIVU (nonzero shamt field)
.word 0x012a005b
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'jalr' instruction panics when the rt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid JALR (nonzero rt field)
.word 0x01495809
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'jalr' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid JALR (nonzero shamt field)
.word 0x00095849
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'jr' instruction panics when the rd field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid JR (nonzero rd field)
.word 0x00095808
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'jr' instruction panics when the rt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid JR (nonzero rt field)
.word 0x01490008
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'jr' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid JR (nonzero shamt field)
.word 0x00090048
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'lui' instruction panics when the rs field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid LUI (nonzero rs field)
.word 0x3d200280
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'mfhi' instruction panics when the rs field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid MFHI (nonzero rs field)
.word 0x01205810
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'mfhi' instruction panics when the rt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid MFHI (nonzero rt field)
.word 0x000a5810
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'mfhi' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid MFHI (nonzero shamt field)
.word 0x00005850
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'mflo' instruction panics when the rs field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid MFLO (nonzero rs field)
.word 0x01205812
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'mflo' instruction panics when the rt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid MFLO (nonzero rt field)
.word 0x000a5812
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'mflo' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid MFLO (nonzero shamt field)
.word 0x00005852
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'mthi' instruction panics when the rd field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid MTHI (nonzero rd field)
.word 0x000a5811
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'mthi' instruction panics when the rt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid MTHI (nonzero rt field)
.word 0x000a4811
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'mthi' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid MTHI (nonzero shamt field)
.word 0x00004851
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'mtlo' instruction panics when the rd field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid MTLO (nonzero rd field)
.word 0x000a5813
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'mtlo' instruction panics when the rt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid MTLO (nonzero rt field)
.word 0x000a4813
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'mtlo' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid MTLO (nonzero shamt field)
.word 0x00004853
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'mult' instruction panics when the rd field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid MULT (nonzero rd field)
.word 0x000a5818
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'mult' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid MULT (nonzero shamt field)
.word 0x012a0058
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'multu' instruction panics when the rd field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid MULTU (nonzero rd field)
.word 0x000a5819
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'multu' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid MULTU (nonzero shamt field)
.word 0x012a0059
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'nor' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid NOR (nonzero shamt field)
.word 0x012a5867
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'or' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid OR (nonzero shamt field)
.word 0x012a5865
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'sll' instruction panics when the rs field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid SLL (nonzero SHAMT)
.word 0x00200000
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'sll' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid SLL (nonzero shamt field)
.word 0x012a5840
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'slt' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid SLT (nonzero shamt field)
.word 0x012a586a
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'sltu' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid SLTU (nonzero shamt field)
.word 0x012a586b
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'sra' instruction panics when the rs field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid SRA (nonzero rs field)
.word 0x012a5803
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'sra' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid SRA (nonzero shamt field)
.word 0x012a5843
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'srl' instruction panics when the rs field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid SRL (nonzero rs field)
.word 0x012a5802
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'srl' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid SRL (nonzero shamt field)
.word 0x012a5842
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'sub' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid SUB (nonzero shamt field)
.word 0x012a5862
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'subu' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid SUBU (nonzero shamt field)
.word 0x012a5863
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'sync' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid SYNC (nonzero shamt field)
.word 0x0000004f
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
###############################################################################
# Description:
# Tests that the 'xor' instruction panics when the shamt field is nonzero.
#
###############################################################################
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
lui $s0, 0xbfff
ori $s0, 0xfff0
ori $s1, $0, 1
# Invalid XOR (nonzero shamt field)
.word 0x012a5866
sw $zero, 8($s0)
sw $s1, 4($s0)
$done:
jr $ra
nop
.end test
...@@ -79,6 +79,8 @@ func RunVMTests_OpenMips[T mipsevm.FPVMState](t *testing.T, stateFactory StateFa ...@@ -79,6 +79,8 @@ func RunVMTests_OpenMips[T mipsevm.FPVMState](t *testing.T, stateFactory StateFa
require.NotEqual(t, uint32(EndAddr), us.GetState().GetPC(), "must not reach end") require.NotEqual(t, uint32(EndAddr), us.GetState().GetPC(), "must not reach end")
require.True(t, us.GetState().GetExited(), "must set exited state") require.True(t, us.GetState().GetExited(), "must set exited state")
require.Equal(t, uint8(1), us.GetState().GetExitCode(), "must exit with 1") require.Equal(t, uint8(1), us.GetState().GetExitCode(), "must exit with 1")
} else if expectPanic {
require.NotEqual(t, uint32(EndAddr), us.GetState().GetPC(), "must not reach end")
} else { } else {
require.Equal(t, uint32(EndAddr), us.GetState().GetPC(), "must reach end") require.Equal(t, uint32(EndAddr), us.GetState().GetPC(), "must reach end")
done, result := state.GetMemory().GetMemory(BaseAddrEnd+4), state.GetMemory().GetMemory(BaseAddrEnd+8) done, result := state.GetMemory().GetMemory(BaseAddrEnd+4), state.GetMemory().GetMemory(BaseAddrEnd+8)
......
...@@ -140,11 +140,11 @@ ...@@ -140,11 +140,11 @@
"sourceCodeHash": "0x3ff4a3f21202478935412d47fd5ef7f94a170402ddc50e5c062013ce5544c83f" "sourceCodeHash": "0x3ff4a3f21202478935412d47fd5ef7f94a170402ddc50e5c062013ce5544c83f"
}, },
"src/cannon/MIPS.sol": { "src/cannon/MIPS.sol": {
"initCodeHash": "0x8c59913b880e1529a543657e24ac30b17c2ce901b4309211b5c2bc703219271d", "initCodeHash": "0xc783f01a426b889cd80d242cf01901fc34c595e59e74d50e3a0a8cb1fa226b3f",
"sourceCodeHash": "0xfa6e6eacba6be2c9489f828f8a50dda40565eef5c73a2cf8e274e1fd4410d38a" "sourceCodeHash": "0xfa6e6eacba6be2c9489f828f8a50dda40565eef5c73a2cf8e274e1fd4410d38a"
}, },
"src/cannon/MIPS2.sol": { "src/cannon/MIPS2.sol": {
"initCodeHash": "0xf3ff16b352e256534761844d49e159c267dd09e79bc9ddec78d0c90f8746ea20", "initCodeHash": "0xeac747751362183e6e0e4caa34f07284823449867897a39bd036db5ea189e2c7",
"sourceCodeHash": "0x115bd6a4c4d77ed210dfd468675b409fdae9f79b932063c138f0765ba9063462" "sourceCodeHash": "0x115bd6a4c4d77ed210dfd468675b409fdae9f79b932063c138f0765ba9063462"
}, },
"src/cannon/PreimageOracle.sol": { "src/cannon/PreimageOracle.sol": {
......
...@@ -122,6 +122,9 @@ library MIPSInstructions { ...@@ -122,6 +122,9 @@ library MIPSInstructions {
} }
} }
// Verify that the instruction is properly encoded.
checkZeroEncoding(_insn);
// ALU // ALU
// Note: swr outputs more than 4 bytes without the mask 0xffFFffFF // Note: swr outputs more than 4 bytes without the mask 0xffFFffFF
uint32 val = executeMipsInstruction(_insn, _opcode, _fun, rs, rt, mem) & 0xffFFffFF; uint32 val = executeMipsInstruction(_insn, _opcode, _fun, rs, rt, mem) & 0xffFFffFF;
...@@ -170,6 +173,81 @@ library MIPSInstructions { ...@@ -170,6 +173,81 @@ library MIPSInstructions {
} }
} }
/// @notice Checks if an instruction is properly encoded with zeroes in the right places as per
/// the MIPS instruction encoding rules defined in the MIPS specification. Reverts if
/// the instruction is not properly encoded. Proper encoding is generally not harmful
/// but can potentially have side-effects for specific opcodes.
/// @param _insn Encoded instruction to check.
function checkZeroEncoding(uint32 _insn) internal pure {
// Pick out the opcode and function code.
uint8 opcode = uint8(_insn >> 26);
uint8 func = uint8(_insn & 0x3F);
// Pick out the registers.
uint8 rs = uint8((_insn >> 21) & 0x1F);
uint8 rt = uint8((_insn >> 16) & 0x1F);
uint8 rd = uint8((_insn >> 11) & 0x1F);
uint8 shamt = uint8((_insn >> 6) & 0x1F);
// Checks for R-type instructions.
if (opcode == 0x00) {
// Check for zero rs.
if (
// SLL, SRL, SRA
func == 0x00 || func == 0x02 || func == 0x03
// MFHI, MFLO
|| func == 0x10 || func == 0x12
) {
require(rs == 0, "MIPS: rs not zero");
}
// Check for zero rt.
if (
// JR, JALR
func == 0x08 || func == 0x09
// MFHI, MFLO, MTHI, MTLO
|| (func >= 0x10 && func <= 0x13)
) {
require(rt == 0, "MIPS: rt not zero");
}
// Check for zero rd.
if (
// JR
func == 0x08
// MTHI, MTLO
|| func == 0x11 || func == 0x13
// MULT, MULTU, DIV, DIVU
|| (func >= 0x18 && func <= 0x1B)
) {
require(rd == 0, "MIPS: rd not zero");
}
// Check for zero shamt.
if (
// JR, JALR
func == 0x08 || func == 0x09
// SYNC
|| func == 0x0F
// MFHI, MFLO, MTHI, MTLO
|| (func >= 0x10 && func <= 0x13)
// MULT, MULTU, DIV, DIVU
|| (func >= 0x18 && func <= 0x1B)
// ADD, ADDU, SUB, SUBU, AND, OR, XOR, NOR
|| (func >= 0x20 && func <= 0x27)
// SLT, SLTU
|| func == 0x2A || func == 0x2B
) {
require(shamt == 0, "MIPS: shamt not zero");
}
}
// Check for zero rs in LUI.
if (opcode == 0x0F) {
require(rs == 0, "MIPS: rs not zero");
}
}
/// @notice Execute an instruction. /// @notice Execute an instruction.
function executeMipsInstruction( function executeMipsInstruction(
uint32 _insn, uint32 _insn,
......
...@@ -27,7 +27,7 @@ contract DeploymentSummary is DeploymentSummaryCode { ...@@ -27,7 +27,7 @@ contract DeploymentSummary is DeploymentSummaryCode {
address internal constant l1StandardBridgeProxyAddress = 0x20A42a5a785622c6Ba2576B2D6e924aA82BFA11D; address internal constant l1StandardBridgeProxyAddress = 0x20A42a5a785622c6Ba2576B2D6e924aA82BFA11D;
address internal constant l2OutputOracleAddress = 0x19652082F846171168Daf378C4fD3ee85a0D4A60; address internal constant l2OutputOracleAddress = 0x19652082F846171168Daf378C4fD3ee85a0D4A60;
address internal constant l2OutputOracleProxyAddress = 0x39Af23E00F1e662025aA01b0cEdA19542B78DF99; address internal constant l2OutputOracleProxyAddress = 0x39Af23E00F1e662025aA01b0cEdA19542B78DF99;
address internal constant mipsAddress = 0x3629E5c6FCCaA06C25aD8Fe5c9de82d7A39E9Df8; address internal constant mipsAddress = 0x2875d50F393FfE847bFD3D517E80097b87f10928;
address internal constant optimismMintableERC20FactoryAddress = 0x39Aea2Dd53f2d01c15877aCc2791af6BDD7aD567; address internal constant optimismMintableERC20FactoryAddress = 0x39Aea2Dd53f2d01c15877aCc2791af6BDD7aD567;
address internal constant optimismMintableERC20FactoryProxyAddress = 0xc7B87b2b892EA5C3CfF47168881FE168C00377FB; address internal constant optimismMintableERC20FactoryProxyAddress = 0xc7B87b2b892EA5C3CfF47168881FE168C00377FB;
address internal constant optimismPortalAddress = 0xbdD90485FCbcac869D5b5752179815a3103d8131; address internal constant optimismPortalAddress = 0xbdD90485FCbcac869D5b5752179815a3103d8131;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -27,7 +27,7 @@ contract DeploymentSummaryFaultProofs is DeploymentSummaryFaultProofsCode { ...@@ -27,7 +27,7 @@ contract DeploymentSummaryFaultProofs is DeploymentSummaryFaultProofsCode {
address internal constant l1StandardBridgeProxyAddress = 0x20A42a5a785622c6Ba2576B2D6e924aA82BFA11D; address internal constant l1StandardBridgeProxyAddress = 0x20A42a5a785622c6Ba2576B2D6e924aA82BFA11D;
address internal constant l2OutputOracleAddress = 0x19652082F846171168Daf378C4fD3ee85a0D4A60; address internal constant l2OutputOracleAddress = 0x19652082F846171168Daf378C4fD3ee85a0D4A60;
address internal constant l2OutputOracleProxyAddress = 0x39Af23E00F1e662025aA01b0cEdA19542B78DF99; address internal constant l2OutputOracleProxyAddress = 0x39Af23E00F1e662025aA01b0cEdA19542B78DF99;
address internal constant mipsAddress = 0x3629E5c6FCCaA06C25aD8Fe5c9de82d7A39E9Df8; address internal constant mipsAddress = 0x2875d50F393FfE847bFD3D517E80097b87f10928;
address internal constant optimismMintableERC20FactoryAddress = 0x39Aea2Dd53f2d01c15877aCc2791af6BDD7aD567; address internal constant optimismMintableERC20FactoryAddress = 0x39Aea2Dd53f2d01c15877aCc2791af6BDD7aD567;
address internal constant optimismMintableERC20FactoryProxyAddress = 0xc7B87b2b892EA5C3CfF47168881FE168C00377FB; address internal constant optimismMintableERC20FactoryProxyAddress = 0xc7B87b2b892EA5C3CfF47168881FE168C00377FB;
address internal constant optimismPortalAddress = 0xbdD90485FCbcac869D5b5752179815a3103d8131; address internal constant optimismPortalAddress = 0xbdD90485FCbcac869D5b5752179815a3103d8131;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment