Sitelet https://github.com/r55-eth/r55/commit/7bb81bbb5aa7ae3f7f2130d0daa9c4cacba6a39b
Skip to content

Commit 7bb81bb

Browse files
authored
Feat: syscalls enhance (#9)
1 parent bc989b1 commit 7bb81bb

4 files changed

Lines changed: 71 additions & 58 deletions

File tree

‎Cargo.toml‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@
22

33
resolver = "2"
44

5-
members = [ "eth-riscv-interpreter",
6-
"eth-riscv-syscalls", "r55",
7-
]
5+
members = ["eth-riscv-interpreter", "eth-riscv-syscalls", "r55"]
6+
default-members = ["eth-riscv-interpreter", "eth-riscv-syscalls", "r55"]
87

9-
exclude = [ "contract-derive", "erc20", "eth-riscv-runtime" ]
8+
exclude = ["contract-derive", "erc20", "eth-riscv-runtime"]
109

1110
[workspace.package]
1211
version = "0.1.0"
@@ -15,3 +14,5 @@ license = "Apache 2.0"
1514
repository = "https://github.com/leonardoalt/r5"
1615

1716
[workspace.dependencies]
17+
eth-riscv-interpreter = { path = "eth-riscv-interpreter" }
18+
eth-riscv-syscalls = { path = "eth-riscv-syscalls" }

‎eth-riscv-syscalls/src/lib.rs‎

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,22 +44,26 @@ macro_rules! syscalls {
4444
}
4545
}
4646

47-
// Generate `Syscall` enum with supported syscalls and their numbers.
48-
// t0: 0, opcode for return, a0: memory address of data, a1: length of data, in bytes, doesn't return
49-
// t0: 1, opcode for sload, a0: storage key, returns 64-bit value in a0
50-
// t0: 2, opcode for sstore, a0: storage key, a1: storage value, returns nothing
51-
// t0: 3, opcode for call, args: TODO
52-
// t0: 4, opcode for revert, doesn't return
53-
// t0: 5, opcode for caller, returns an address
47+
// Generate `Syscall` enum with supported syscalls and their ids.
48+
//
49+
// The opcode for each syscall matches the corresponding EVM opcode,
50+
// as described on https://www.evm.codes.
51+
//
5452
// t0: 0x20, opcode for keccak256, a0: offset, a1: size, returns keccak256 hash
53+
// t0: 0x33, opcode for caller, returns an address
5554
// t0: 0x34, opcode for callvalue, a0: first limb, a1: second limb, a2: third limb, a3: fourth limb, returns 256-bit value
55+
// t0: 0x54, opcode for sload, a0: storage key, returns 64-bit value in a0
56+
// t0: 0x55, opcode for sstore, a0: storage key, a1: storage value, returns nothing
57+
// t0: 0xf1, opcode for call, args: TODO
58+
// t0: 0xf3, opcode for return, a0: memory address of data, a1: length of data in bytes, doesn't return
59+
// t0: 0xfd, opcode for revert, doesn't return
5660
syscalls!(
57-
(0, Return, "return"),
58-
(1, SLoad, "sload"),
59-
(2, SStore, "sstore"),
60-
(3, Call, "call"),
61-
(4, Revert, "revert"),
62-
(5, Caller, "caller"),
6361
(0x20, Keccak256, "keccak256"),
62+
(0x33, Caller, "caller"),
6463
(0x34, CallValue, "callvalue"),
64+
(0x54, SLoad, "sload"),
65+
(0x55, SStore, "sstore"),
66+
(0xf1, Call, "call"),
67+
(0xf3, Return, "return"),
68+
(0xfd, Revert, "revert")
6569
);

‎r55/Cargo.toml‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ repository.workspace = true
77

88
[dependencies]
99
#revm = { git = "https://github.com/r0qs/revm" }
10+
eth-riscv-interpreter.workspace = true
11+
eth-riscv-syscalls.workspace = true
12+
1013
revm = "9.0.0"
1114
rvemu = { git = "https://github.com/lvella/rvemu.git" }
12-
eth-riscv-interpreter = { git = "https://github.com/leonardoalt/r55" }
13-
eth-riscv-syscalls = { path = "../eth-riscv-syscalls" }
1415
alloy-core = "0.7.4"
1516
alloy-sol-types = "0.7.4"
1617

‎r55/src/exec.rs‎

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,15 @@ struct RVEmu {
7171

7272
fn riscv_context(frame: &Frame) -> Option<RVEmu> {
7373
let interpreter = frame.interpreter();
74-
if matches!(interpreter.bytecode.get(0), Some(0xFF)) {
75-
let emu = setup_from_elf(&interpreter.bytecode[1..], &interpreter.contract.input);
76-
Some(RVEmu {
77-
emu,
78-
returned_data_destiny: None,
79-
})
80-
} else {
81-
None
82-
}
74+
75+
let Some((0xFF, bytecode)) = interpreter.bytecode.split_first() else {
76+
return None;
77+
};
78+
let emu = setup_from_elf(bytecode, &interpreter.contract.input);
79+
Some(RVEmu {
80+
emu,
81+
returned_data_destiny: None,
82+
})
8383
}
8484

8585
pub fn handle_register<EXT, DB: Database>(handler: &mut EvmHandler<'_, EXT, DB>) {
@@ -133,7 +133,11 @@ fn execute_riscv(
133133
let emu = &mut rvemu.emu;
134134
let returned_data_destiny = &mut rvemu.returned_data_destiny;
135135
if let Some(destiny) = std::mem::take(returned_data_destiny) {
136-
let data = emu.cpu.bus.get_dram_slice(destiny).unwrap();
136+
let data = emu
137+
.cpu
138+
.bus
139+
.get_dram_slice(destiny)
140+
.unwrap_or_else(|e| panic!("Unable to get destiny dram slice ({e:?})"));
137141
data.copy_from_slice(shared_memory.slice(0, data.len()))
138142
}
139143

@@ -154,18 +158,18 @@ fn execute_riscv(
154158
match run_result {
155159
Err(Exception::EnvironmentCallFromMMode) => {
156160
let t0: u64 = emu.cpu.xregs.read(5);
157-
match Syscall::try_from(t0 as u8) {
158-
Ok(Syscall::Return) => {
161+
162+
let Ok(syscall) = Syscall::try_from(t0 as u8) else {
163+
println!("Unhandled syscall: {:?}", t0);
164+
return return_revert(interpreter);
165+
};
166+
167+
match syscall {
168+
Syscall::Return => {
159169
let ret_offset: u64 = emu.cpu.xregs.read(10);
160170
let ret_size: u64 = emu.cpu.xregs.read(11);
161-
let data_bytes = if ret_size != 0 {
162-
emu.cpu
163-
.bus
164-
.get_dram_slice(ret_offset..(ret_offset + ret_size))
165-
.unwrap()
166-
} else {
167-
&mut []
168-
};
171+
let data_bytes = dram_slice(emu, ret_offset, ret_size);
172+
169173
return InterpreterAction::Return {
170174
result: InterpreterResult {
171175
result: InstructionResult::Return,
@@ -174,7 +178,7 @@ fn execute_riscv(
174178
},
175179
};
176180
}
177-
Ok(Syscall::SLoad) => {
181+
Syscall::SLoad => {
178182
let key: u64 = emu.cpu.xregs.read(10);
179183
match host.sload(interpreter.contract.target_address, U256::from(key)) {
180184
Some((value, _is_cold)) => {
@@ -185,7 +189,7 @@ fn execute_riscv(
185189
}
186190
}
187191
}
188-
Ok(Syscall::SStore) => {
192+
Syscall::SStore => {
189193
let key: u64 = emu.cpu.xregs.read(10);
190194
let value: u64 = emu.cpu.xregs.read(11);
191195
host.sstore(
@@ -194,7 +198,7 @@ fn execute_riscv(
194198
U256::from(value),
195199
);
196200
}
197-
Ok(Syscall::Call) => {
201+
Syscall::Call => {
198202
let a0: u64 = emu.cpu.xregs.read(10);
199203
let address =
200204
Address::from_slice(emu.cpu.bus.get_dram_slice(a0..(a0 + 20)).unwrap());
@@ -230,7 +234,7 @@ fn execute_riscv(
230234
}),
231235
};
232236
}
233-
Ok(Syscall::Revert) => {
237+
Syscall::Revert => {
234238
return InterpreterAction::Return {
235239
result: InterpreterResult {
236240
result: InstructionResult::Revert,
@@ -239,7 +243,7 @@ fn execute_riscv(
239243
},
240244
};
241245
}
242-
Ok(Syscall::Caller) => {
246+
Syscall::Caller => {
243247
let caller = interpreter.contract.caller;
244248
// Break address into 3 u64s and write to registers
245249
let caller_bytes = caller.as_slice();
@@ -253,15 +257,10 @@ fn execute_riscv(
253257
let third_u64 = u64::from_be_bytes(padded_bytes);
254258
emu.cpu.xregs.write(12, third_u64);
255259
}
256-
Ok(Syscall::Keccak256) => {
257-
let offset: u64 = emu.cpu.xregs.read(10);
258-
let size: u64 = emu.cpu.xregs.read(11);
259-
260-
let data_bytes = if size != 0 {
261-
emu.cpu.bus.get_dram_slice(offset..(offset + size)).unwrap()
262-
} else {
263-
&mut []
264-
};
260+
Syscall::Keccak256 => {
261+
let ret_offset: u64 = emu.cpu.xregs.read(10);
262+
let ret_size: u64 = emu.cpu.xregs.read(11);
263+
let data_bytes = dram_slice(emu, ret_offset, ret_size);
265264

266265
let mut hasher = Keccak256::new();
267266
hasher.update(data_bytes);
@@ -281,18 +280,14 @@ fn execute_riscv(
281280
.xregs
282281
.write(13, u64::from_le_bytes(hash[24..32].try_into().unwrap()));
283282
}
284-
Ok(Syscall::CallValue) => {
283+
Syscall::CallValue => {
285284
let value = interpreter.contract.call_value;
286285
let limbs = value.into_limbs();
287286
emu.cpu.xregs.write(10, limbs[0]);
288287
emu.cpu.xregs.write(11, limbs[1]);
289288
emu.cpu.xregs.write(12, limbs[2]);
290289
emu.cpu.xregs.write(13, limbs[3]);
291290
}
292-
_ => {
293-
println!("Unhandled syscall: {:?}", t0);
294-
return return_revert(interpreter);
295-
}
296291
}
297292
}
298293
_ => {
@@ -301,3 +296,15 @@ fn execute_riscv(
301296
}
302297
}
303298
}
299+
300+
/// Returns RISC-V DRAM slice in a given size range, starts with a given offset
301+
fn dram_slice(emu: &mut Emulator, ret_offset: u64, ret_size: u64) -> &mut [u8] {
302+
if ret_size != 0 {
303+
emu.cpu
304+
.bus
305+
.get_dram_slice(ret_offset..(ret_offset + ret_size))
306+
.unwrap()
307+
} else {
308+
&mut []
309+
}
310+
}

0 commit comments

Comments
 (0)