Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve todos in the codebase #90

Merged
merged 9 commits into from
Oct 31, 2024
3 changes: 3 additions & 0 deletions rvgo/fast/instrumented.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ func (m *InstrumentedState) readPreimage(key [32]byte, offset uint64) (dat [32]b
m.lastPreimage = preimage
}
m.lastPreimageOffset = offset
if offset >= uint64(len(preimage)) {
panic("Preimage offset out-of-bounds")
}
datLen = uint64(copy(dat[:], preimage[offset:]))
return
}
Expand Down
1 change: 0 additions & 1 deletion rvgo/fast/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,6 @@ func (m *Memory) pageLookup(pageIndex uint64) (*CachedPage, bool) {
return p, ok
}

// TODO: we never do unaligned writes, this should be simplified
func (m *Memory) SetUnaligned(addr uint64, dat []byte) {
if len(dat) > 32 {
panic("cannot set more than 32 bytes")
Expand Down
4 changes: 0 additions & 4 deletions rvgo/fast/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,3 @@ func parseRs2(instr U64) U64 {
func parseFunct7(instr U64) U64 {
return shr64(toU64(25), instr)
}

func parseCSSR(instr U64) U64 {
return shr64(toU64(20), instr)
}
85 changes: 32 additions & 53 deletions rvgo/fast/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,33 +266,6 @@ func (inst *InstrumentedState) riscvStep() (outErr error) {
s.Memory.SetUnaligned(rightAddr, bytez[leftSize:size])
}

//
// CSR (control and status registers) functions
//
readCSR := func(num U64) U64 {
// TODO: do we need CSR?
return toU64(0)
}

writeCSR := func(num U64, v U64) {
// TODO: do we need CSR?
}

updateCSR := func(num U64, v U64, mode U64) (out U64) {
out = readCSR(num)
switch mode {
case 1: // ?01 = CSRRW(I)
case 2: // ?10 = CSRRS(I)
v = or64(out, v)
case 3: // ?11 = CSRRC(I)
v = and64(out, not64(v))
default:
revertWithCode(riscv.ErrUnknownCSRMode, fmt.Errorf("unknown CSR mode: %d", mode))
}
writeCSR(num, v)
return
}

//
// Preimage oracle interactions
//
Expand Down Expand Up @@ -390,28 +363,39 @@ func (inst *InstrumentedState) riscvStep() (outErr error) {
// A1 = n (length)
length := getRegister(toU64(11))
// A2 = prot (memory protection type, can ignore)
// A3 = flags (shared with other process and or written back to file, can ignore) // TODO maybe assert the MAP_ANONYMOUS flag is set
// A3 = flags (shared with other process and or written back to file)
flags := getRegister(toU64(13))
// A4 = fd (file descriptor, can ignore because we support anon memory only)
fd := getRegister(toU64(14))
// A5 = offset (offset in file, we don't support any non-anon memory, so we can ignore this)

// ignore: prot, flags, fd, offset
switch addr {
case 0:
// No hint, allocate it ourselves, by as much as the requested length.
// Increase the length to align it with desired page size if necessary.
align := and64(length, shortToU64(4095))
if align != 0 {
length = add64(length, sub64(shortToU64(4096), align))
errCode := toU64(0)

// ensure MAP_ANONYMOUS is set and fd == -1
if (flags&0x20) == 0 || fd != u64Mask() {
addr = u64Mask()
errCode = toU64(0x4d) // EBADF
} else {
// ignore: prot, flags, fd, offset
switch addr {
case 0:
// No hint, allocate it ourselves, by as much as the requested length.
// Increase the length to align it with desired page size if necessary.
align := and64(length, shortToU64(4095))
if align != 0 {
length = add64(length, sub64(shortToU64(4096), align))
}
prevHeap := getHeap()
addr = prevHeap
setHeap(add64(prevHeap, length)) // increment heap with length
//fmt.Printf("mmap: 0x%016x (+ 0x%x increase)\n", s.Heap, length)
default:
// allow hinted memory address (leave it in A0 as return argument)
//fmt.Printf("mmap: 0x%016x (0x%x allowed)\n", addr, length)
}
prevHeap := getHeap()
setRegister(toU64(10), prevHeap)
setHeap(add64(prevHeap, length)) // increment heap with length
//fmt.Printf("mmap: 0x%016x (+ 0x%x increase)\n", s.Heap, length)
default:
// allow hinted memory address (leave it in A0 as return argument)
//fmt.Printf("mmap: 0x%016x (0x%x allowed)\n", addr, length)
}
setRegister(toU64(11), toU64(0)) // no error
setRegister(toU64(10), addr)
setRegister(toU64(11), errCode)
case riscv.SysRead: // read
fd := getRegister(toU64(10)) // A0 = fd
addr := getRegister(toU64(11)) // A1 = *buf addr
Expand Down Expand Up @@ -867,14 +851,7 @@ func (inst *InstrumentedState) riscvStep() (outErr error) {
setPC(add64(pc, toU64(4))) // ignore breakpoint
}
default: // CSR instructions
imm := parseCSSR(instr)
value := rs1
if iszero64(and64(funct3, toU64(4))) {
value = getRegister(rs1)
}
mode := and64(funct3, toU64(3))
rdValue := updateCSR(imm, value, mode)
setRegister(rd, rdValue)
setRegister(rd, 0) // ignore CSR instructions
setPC(add64(pc, toU64(4)))
}
case 0x2F: // 010_1111: RV32A and RV32A atomic operations extension
Expand All @@ -894,7 +871,9 @@ func (inst *InstrumentedState) riscvStep() (outErr error) {
revertWithCode(riscv.ErrBadAMOSize, fmt.Errorf("bad AMO size: %d", size))
}
addr := getRegister(rs1)
// TODO check if addr is aligned
if addr&3 != 0 { // quick addr alignment check
mininny marked this conversation as resolved.
Show resolved Hide resolved
revertWithCode(riscv.ErrNotAlignedAddr, fmt.Errorf("addr %d not aligned with 4 bytes", addr))
}

op := shr64(toU64(2), funct7)
switch op {
Expand Down
1 change: 0 additions & 1 deletion rvgo/riscv/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ const (
ErrUnexpectedRProofLoad = uint64(0xbad22220)
ErrUnexpectedRProofStoreUnaligned = uint64(0xbad22221)
ErrUnexpectedRProofStore = uint64(0xbad2222f)
ErrUnknownCSRMode = uint64(0xbadc0de0)
ErrBadAMOSize = uint64(0xbada70)
ErrFailToReadPreimage = uint64(0xbadf00d0)
ErrBadMemoryProof = uint64(0xbadf00d1)
Expand Down
4 changes: 0 additions & 4 deletions rvgo/slow/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,3 @@ func parseRs2(instr U64) U64 {
func parseFunct7(instr U64) U64 {
return shr64(toU64(25), instr)
}

func parseCSSR(instr U64) U64 {
return shr64(toU64(20), instr)
}
99 changes: 40 additions & 59 deletions rvgo/slow/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,6 @@ func Step(calldata []byte, po PreimageOracle) (stateHash common.Hash, outErr err
copy(out[:], calldata[offset.val():])
return
}
// TODO check length
// TODO check calldata stateData size

// TODO: validate abi offset values?

stateContentOffset := uint8(4 + 32 + 32 + 32 + 32)
if iszero(eq(b32asBEWord(calldataload(toU64(4+32*3))), shortToU256(stateSize))) {
Expand All @@ -133,10 +129,16 @@ func Step(calldata []byte, po PreimageOracle) (stateHash common.Hash, outErr err

proofContentOffset := shortToU64(uint16(stateContentOffset) + paddedStateSize + 32)

if and(b32asBEWord(calldataload(shortToU64(uint16(stateContentOffset)+paddedStateSize))), shortToU256(60-1)) != (U256{}) {
// proof offset must be stateContentOffset+paddedStateSize+32
// proof size: 64-5+1=60 * 32 byte leaf,
// but multiple memProof can be used, so the proofSize must be a multiple of 60
panic("invalid proof offset input")
}

//
// State loading
//
// TODO
stateData := make([]byte, stateSize)
copy(stateData, calldata[stateContentOffset:])

Expand Down Expand Up @@ -454,33 +456,6 @@ func Step(calldata []byte, po PreimageOracle) (stateHash common.Hash, outErr err
storeMemUnaligned(addr, size, u64ToU256(value), proofIndexL, proofIndexR)
}

//
// CSR (control and status registers) functions
//
readCSR := func(num U64) U64 {
// TODO: do we need CSR?
return toU64(0)
}

writeCSR := func(num U64, v U64) {
// TODO: do we need CSR?
}

updateCSR := func(num U64, v U64, mode U64) (out U64) {
out = readCSR(num)
switch mode.val() {
case 1: // ?01 = CSRRW(I)
case 2: // ?10 = CSRRS(I)
v = or64(out, v)
case 3: // ?11 = CSRRC(I)
v = and64(out, not64(v))
default:
revertWithCode(riscv.ErrUnknownCSRMode, fmt.Errorf("unknown CSR mode: %d", mode.val()))
}
writeCSR(num, v)
return
}

//
// Preimage oracle interactions
//
Expand Down Expand Up @@ -590,28 +565,39 @@ func Step(calldata []byte, po PreimageOracle) (stateHash common.Hash, outErr err
// A1 = n (length)
length := getRegister(toU64(11))
// A2 = prot (memory protection type, can ignore)
// A3 = flags (shared with other process and or written back to file, can ignore) // TODO maybe assert the MAP_ANONYMOUS flag is set
// A3 = flags (shared with other process and or written back to file)
flags := getRegister(toU64(13))
// A4 = fd (file descriptor, can ignore because we support anon memory only)
fd := getRegister(toU64(14))
// A5 = offset (offset in file, we don't support any non-anon memory, so we can ignore this)

// ignore: prot, flags, fd, offset
switch addr.val() {
case 0:
// No hint, allocate it ourselves, by as much as the requested length.
// Increase the length to align it with desired page size if necessary.
align := and64(length, shortToU64(4095))
if align != (U64{}) {
length = add64(length, sub64(shortToU64(4096), align))
errCode := toU64(0)

// ensure MAP_ANONYMOUS is set and fd == -1
if (flags.val()&0x20) == 0 || fd != u64Mask() {
addr = u64Mask()
errCode = toU64(0x4d) // no error
} else {
// ignore: prot, flags, fd, offset
switch addr.val() {
case 0:
// No hint, allocate it ourselves, by as much as the requested length.
// Increase the length to align it with desired page size if necessary.
align := and64(length, shortToU64(4095))
if align != (U64{}) {
length = add64(length, sub64(shortToU64(4096), align))
}
prevHeap := getHeap()
addr = prevHeap
setHeap(add64(prevHeap, length)) // increment heap with length
//fmt.Printf("mmap: 0x%016x (+ 0x%x increase)\n", s.Heap, length)
default:
// allow hinted memory address (leave it in A0 as return argument)
//fmt.Printf("mmap: 0x%016x (0x%x allowed)\n", addr, length)
}
prevHeap := getHeap()
setRegister(toU64(10), prevHeap)
setHeap(add64(prevHeap, length)) // increment heap with length
//fmt.Printf("mmap: 0x%016x (+ 0x%x increase)\n", s.Heap, length)
default:
// allow hinted memory address (leave it in A0 as return argument)
//fmt.Printf("mmap: 0x%016x (0x%x allowed)\n", addr, length)
}
setRegister(toU64(11), toU64(0)) // no error
setRegister(toU64(10), addr)
setRegister(toU64(11), errCode)
case riscv.SysRead: // read
fd := getRegister(toU64(10)) // A0 = fd
addr := getRegister(toU64(11)) // A1 = *buf addr
Expand Down Expand Up @@ -1037,15 +1023,8 @@ func Step(calldata []byte, po PreimageOracle) (stateHash common.Hash, outErr err
default: // imm12 = 000000000001 EBREAK
setPC(add64(pc, toU64(4))) // ignore breakpoint
}
default: // CSR instructions
imm := parseCSSR(instr)
value := rs1
if iszero64(and64(funct3, toU64(4))) {
value = getRegister(rs1)
}
mode := and64(funct3, toU64(3))
rdValue := updateCSR(imm, value, mode)
setRegister(rd, rdValue)
default: // ignore CSR instructions
setRegister(rd, toU64(0)) // ignore CSR instructions
setPC(add64(pc, toU64(4)))
}
case 0x2F: // 010_1111: RV32A and RV32A atomic operations extension
Expand All @@ -1065,7 +1044,9 @@ func Step(calldata []byte, po PreimageOracle) (stateHash common.Hash, outErr err
revertWithCode(riscv.ErrBadAMOSize, fmt.Errorf("bad AMO size: %d", size))
}
addr := getRegister(rs1)
// TODO check if addr is aligned
if and64(addr, toU64(3)) != (U64{}) { // quick addr alignment check
revertWithCode(riscv.ErrNotAlignedAddr, fmt.Errorf("addr %d not aligned with 4 bytes", addr))
}

op := shr64(toU64(2), funct7)
switch op.val() {
Expand Down
10 changes: 8 additions & 2 deletions rvgo/test/syscall_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,8 +384,14 @@ func FuzzStateSyscallMmap(f *testing.F) {
Exited: false,
Memory: fast.NewMemory(),
LoadReservation: 0,
Registers: [32]uint64{17: riscv.SysMmap, 10: addr, 11: length},
Step: step,
Registers: [32]uint64{
17: riscv.SysMmap,
10: addr,
11: length,
13: 32, // MAP_ANONYMOUS flag
14: 0xFFFF_FFFF_FFFF_FFFF, // fd == -1 (u64 mask)
},
Step: step,
}
state.Memory.SetUnaligned(pc, syscallInsn)
preStateRoot := state.Memory.MerkleRoot()
Expand Down
6 changes: 3 additions & 3 deletions rvgo/test/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func TestFastStep(t *testing.T) {
runTestCategory("rv64ui-p")
runTestCategory("rv64um-p")
runTestCategory("rv64ua-p")
//runTestCategory("benchmarks") TODO benchmarks (fix ELF bench data loading and wrap in Go benchmark?)
//runTestCategory("benchmarks") TODO benchmarks (fix ELF bench data loading and wrap in Go benchmark?) https://github.com/ethereum-optimism/asterisc/issues/89
}

func TestSlowStep(t *testing.T) {
Expand All @@ -171,7 +171,7 @@ func TestSlowStep(t *testing.T) {
runTestCategory("rv64ui-p")
runTestCategory("rv64um-p")
runTestCategory("rv64ua-p")
//runTestCategory("benchmarks") TODO benchmarks (fix ELF bench data loading and wrap in Go benchmark?)
//runTestCategory("benchmarks") TODO benchmarks (fix ELF bench data loading and wrap in Go benchmark?) https://github.com/ethereum-optimism/asterisc/issues/89
}

func TestEVMStep(t *testing.T) {
Expand All @@ -184,5 +184,5 @@ func TestEVMStep(t *testing.T) {
runTestCategory("rv64ui-p")
runTestCategory("rv64um-p")
runTestCategory("rv64ua-p")
//runTestCategory("benchmarks") TODO benchmarks (fix ELF bench data loading and wrap in Go benchmark?)
//runTestCategory("benchmarks") TODO benchmarks (fix ELF bench data loading and wrap in Go benchmark?) https://github.com/ethereum-optimism/asterisc/issues/89
}
Loading
Loading