|
1 | 1 | extern crate alloc;
|
2 |
| -use crate::poseidon_sponge::poseidon_sponge_stark::poseidon; |
3 | 2 | use alloc::collections::BTreeMap;
|
4 |
| -use anyhow::{anyhow, bail, Context, Result}; |
5 |
| -use elf::{endian::BigEndian, file::Class, ElfBytes}; |
6 |
| -use plonky2::field::goldilocks_field::GoldilocksField; |
| 3 | +use anyhow::{Context, Result}; |
7 | 4 | use serde::{Deserialize, Serialize};
|
8 | 5 | use std::fs::{self};
|
9 | 6 | use std::io::Read;
|
10 |
| -use zkm_emulator::memory::{INIT_SP, WORD_SIZE}; |
| 7 | +use zkm_emulator::memory::WORD_SIZE; |
11 | 8 | use zkm_emulator::state::{Segment, REGISTERS_START};
|
12 | 9 | pub const PAGE_SIZE: u32 = 4096;
|
13 | 10 |
|
@@ -58,211 +55,6 @@ impl Program {
|
58 | 55 | Ok(true)
|
59 | 56 | }
|
60 | 57 |
|
61 |
| - /// Initialize a MIPS Program from an appropriate ELF file |
62 |
| - pub fn load_elf(input: &[u8], max_mem: u32) -> Result<Program> { |
63 |
| - let mut image: BTreeMap<u32, u32> = BTreeMap::new(); |
64 |
| - let elf = ElfBytes::<BigEndian>::minimal_parse(input) |
65 |
| - .map_err(|err| anyhow!("Elf parse error: {err}"))?; |
66 |
| - if elf.ehdr.class != Class::ELF32 { |
67 |
| - bail!("Not a 32-bit ELF"); |
68 |
| - } |
69 |
| - if elf.ehdr.e_machine != elf::abi::EM_MIPS { |
70 |
| - bail!("Invalid machine type, must be MIPS"); |
71 |
| - } |
72 |
| - if elf.ehdr.e_type != elf::abi::ET_EXEC { |
73 |
| - bail!("Invalid ELF type, must be executable"); |
74 |
| - } |
75 |
| - let entry: u32 = elf |
76 |
| - .ehdr |
77 |
| - .e_entry |
78 |
| - .try_into() |
79 |
| - .map_err(|err| anyhow!("e_entry was larger than 32 bits. {err}"))?; |
80 |
| - if entry >= max_mem || entry % WORD_SIZE as u32 != 0 { |
81 |
| - bail!("Invalid entrypoint"); |
82 |
| - } |
83 |
| - let segments = elf.segments().ok_or(anyhow!("Missing segment table"))?; |
84 |
| - if segments.len() > 256 { |
85 |
| - bail!("Too many program headers"); |
86 |
| - } |
87 |
| - |
88 |
| - let mut hiaddr = 0u32; |
89 |
| - for segment in segments.iter().filter(|x| x.p_type == elf::abi::PT_LOAD) { |
90 |
| - let file_size: u32 = segment |
91 |
| - .p_filesz |
92 |
| - .try_into() |
93 |
| - .map_err(|err| anyhow!("filesize was larger than 32 bits. {err}"))?; |
94 |
| - if file_size >= max_mem { |
95 |
| - bail!("Invalid segment file_size"); |
96 |
| - } |
97 |
| - let mem_size: u32 = segment |
98 |
| - .p_memsz |
99 |
| - .try_into() |
100 |
| - .map_err(|err| anyhow!("mem_size was larger than 32 bits {err}"))?; |
101 |
| - if mem_size >= max_mem { |
102 |
| - bail!("Invalid segment mem_size"); |
103 |
| - } |
104 |
| - let vaddr: u32 = segment |
105 |
| - .p_vaddr |
106 |
| - .try_into() |
107 |
| - .map_err(|err| anyhow!("vaddr is larger than 32 bits. {err}"))?; |
108 |
| - if vaddr % WORD_SIZE as u32 != 0 { |
109 |
| - bail!("vaddr {vaddr:08x} is unaligned"); |
110 |
| - } |
111 |
| - |
112 |
| - let a = vaddr + mem_size; |
113 |
| - if a > hiaddr { |
114 |
| - hiaddr = a; |
115 |
| - } |
116 |
| - |
117 |
| - let offset: u32 = segment |
118 |
| - .p_offset |
119 |
| - .try_into() |
120 |
| - .map_err(|err| anyhow!("offset is larger than 32 bits. {err}"))?; |
121 |
| - for i in (0..mem_size).step_by(WORD_SIZE) { |
122 |
| - let addr = vaddr.checked_add(i).context("Invalid segment vaddr")?; |
123 |
| - if addr >= max_mem { |
124 |
| - bail!("Address [0x{addr:08x}] exceeds maximum address for guest programs [0x{max_mem:08x}]"); |
125 |
| - } |
126 |
| - if i >= file_size { |
127 |
| - // Past the file size, all zeros. |
128 |
| - image.insert(addr, 0); |
129 |
| - } else { |
130 |
| - let mut word = 0; |
131 |
| - // Don't read past the end of the file. |
132 |
| - let len = core::cmp::min(file_size - i, WORD_SIZE as u32); |
133 |
| - for j in 0..len { |
134 |
| - let offset = (offset + i + j) as usize; |
135 |
| - let byte = input.get(offset).context("Invalid segment offset")?; |
136 |
| - word |= (*byte as u32) << (j * 8); |
137 |
| - } |
138 |
| - image.insert(addr, word); |
139 |
| - } |
140 |
| - } |
141 |
| - } |
142 |
| - |
143 |
| - let brk = hiaddr - (hiaddr & (PAGE_SIZE - 1)) + PAGE_SIZE; |
144 |
| - |
145 |
| - let (symtab, strtab) = elf |
146 |
| - .symbol_table() |
147 |
| - .expect("Failed to read symbol table") |
148 |
| - .expect("Failed to find symbol table"); |
149 |
| - |
150 |
| - // PatchGO |
151 |
| - for symbol in symtab.iter() { |
152 |
| - let name = strtab |
153 |
| - .get(symbol.st_name as usize) |
154 |
| - .expect("Failed to get name from strtab"); |
155 |
| - |
156 |
| - let addr: u32 = symbol |
157 |
| - .st_value |
158 |
| - .try_into() |
159 |
| - .map_err(|err| anyhow!("offset is larger than 32 bits. {err}"))?; |
160 |
| - |
161 |
| - match name { |
162 |
| - "runtime.gcenable" | |
163 |
| - "runtime.init.5" | // patch out: init() { go forcegchelper() } |
164 |
| - "runtime.main.func1" | // patch out: main.func() { newm(sysmon, ....) } |
165 |
| - "runtime.deductSweepCredit" | // uses floating point nums and interacts with gc we disabled |
166 |
| - "runtime.(*gcControllerState).commit" | |
167 |
| - // these prometheus packages rely on concurrent background things. We cannot run those. |
168 |
| - "github.com/prometheus/client_golang/prometheus.init" | |
169 |
| - "github.com/prometheus/client_golang/prometheus.init.0" | |
170 |
| - "github.com/prometheus/procfs.init" | |
171 |
| - "github.com/prometheus/common/model.init" | |
172 |
| - "github.com/prometheus/client_model/go.init" | |
173 |
| - "github.com/prometheus/client_model/go.init.0" | |
174 |
| - "github.com/prometheus/client_model/go.init.1" | |
175 |
| - // skip flag pkg init, we need to debug arg-processing more to see why this fails |
176 |
| - "flag.init" | |
177 |
| - // We need to patch this out, we don't pass float64nan because we don't support floats |
178 |
| - "runtime.check" => { |
179 |
| - // MIPS32 patch: ret (pseudo instruction) |
180 |
| - // 03e00008 = jr $ra = ret (pseudo instruction) |
181 |
| - // 00000000 = nop (executes with delay-slot, but does nothing) |
182 |
| - image.insert(addr, 0x0800e003); |
183 |
| - image.insert(addr + 4, 0); |
184 |
| - }, |
185 |
| - "runtime.MemProfileRate" => { image.insert(addr, 0) ; }, |
186 |
| - &_ => (), |
187 |
| - } |
188 |
| - } |
189 |
| - |
190 |
| - // PatchStack |
191 |
| - let mut sp = INIT_SP - 4 * PAGE_SIZE; |
192 |
| - // allocate 1 page for the initial stack data, and 16KB = 4 pages for the stack to grow |
193 |
| - for i in (0..5 * PAGE_SIZE).step_by(WORD_SIZE) { |
194 |
| - image.insert(sp + i, 0); |
195 |
| - } |
196 |
| - |
197 |
| - sp = INIT_SP; |
198 |
| - // init argc, argv, aux on stack |
199 |
| - image.insert(sp + 4, 0x42u32.to_be()); // argc = 0 (argument count) |
200 |
| - image.insert(sp + 4 * 2, 0x35u32.to_be()); // argv[n] = 0 (terminating argv) |
201 |
| - image.insert(sp + 4 * 3, 0); // envp[term] = 0 (no env vars) |
202 |
| - image.insert(sp + 4 * 4, 6u32.to_be()); // auxv[0] = _AT_PAGESZ = 6 (key) |
203 |
| - image.insert(sp + 4 * 5, 4096u32.to_be()); // auxv[1] = page size of 4 KiB (value) - (== minPhysPageSize) |
204 |
| - image.insert(sp + 4 * 6, 25u32.to_be()); // auxv[2] = AT_RANDOM |
205 |
| - image.insert(sp + 4 * 7, (sp + 4 * 9).to_be()); // auxv[3] = address of 16 bytes containing random value |
206 |
| - image.insert(sp + 4 * 8, 0); // auxv[term] = 0 |
207 |
| - |
208 |
| - image.insert(sp + 4 * 9, 0x34322343u32.to_be()); |
209 |
| - image.insert(sp + 4 * 10, 0x54323423u32.to_be()); |
210 |
| - image.insert(sp + 4 * 11, 0x44572234u32.to_be()); |
211 |
| - image.insert(sp + 4 * 12, 0x90032dd2u32.to_be()); |
212 |
| - |
213 |
| - let mut gprs = [0; 32]; |
214 |
| - gprs[29] = INIT_SP as usize; |
215 |
| - |
216 |
| - let lo = 0; |
217 |
| - let hi = 0; |
218 |
| - let heap = 0x20000000; |
219 |
| - let end_pc: u32 = 0; |
220 |
| - |
221 |
| - // this is just for test |
222 |
| - let mut final_data = [0u8; 36]; |
223 |
| - let page_hash_root = [1u8; 32]; |
224 |
| - final_data[0..32].copy_from_slice(&page_hash_root); |
225 |
| - final_data[32..].copy_from_slice(&end_pc.to_be_bytes()); |
226 |
| - |
227 |
| - let image_id_u64s = poseidon::<GoldilocksField>(&final_data); |
228 |
| - let image_id = image_id_u64s |
229 |
| - .iter() |
230 |
| - .flat_map(|&num| num.to_le_bytes()) |
231 |
| - .collect::<Vec<_>>(); |
232 |
| - |
233 |
| - let pre_hash_root = [1u8; 32]; |
234 |
| - final_data[0..32].copy_from_slice(&pre_hash_root); |
235 |
| - final_data[32..].copy_from_slice(&entry.to_be_bytes()); |
236 |
| - |
237 |
| - let pre_image_id_u64s = poseidon::<GoldilocksField>(&final_data); |
238 |
| - let pre_image_id = pre_image_id_u64s |
239 |
| - .iter() |
240 |
| - .flat_map(|&num| num.to_le_bytes()) |
241 |
| - .collect::<Vec<_>>(); |
242 |
| - |
243 |
| - Ok(Program { |
244 |
| - entry, |
245 |
| - next_pc: (entry + 4) as usize, |
246 |
| - image, |
247 |
| - gprs, |
248 |
| - lo, |
249 |
| - hi, |
250 |
| - heap, |
251 |
| - brk: brk as usize, |
252 |
| - local_user: 0, |
253 |
| - end_pc: end_pc as usize, |
254 |
| - step: 0, |
255 |
| - image_id: image_id.try_into().unwrap(), |
256 |
| - pre_image_id: pre_image_id.try_into().unwrap(), |
257 |
| - pre_hash_root, |
258 |
| - page_hash_root, |
259 |
| - input_stream: Vec::new(), |
260 |
| - input_stream_ptr: 0, |
261 |
| - public_values_stream: Vec::new(), |
262 |
| - public_values_stream_ptr: 0, |
263 |
| - }) |
264 |
| - } |
265 |
| - |
266 | 58 | pub fn load_segment<T: Read>(reader: T) -> Result<Program> {
|
267 | 59 | let segment: Segment = serde_json::from_reader(reader).unwrap();
|
268 | 60 |
|
@@ -346,36 +138,3 @@ impl Program {
|
346 | 138 | })
|
347 | 139 | }
|
348 | 140 | }
|
349 |
| - |
350 |
| -#[cfg(test)] |
351 |
| -mod test { |
352 |
| - use crate::cpu::kernel::elf::*; |
353 |
| - use std::fs::File; |
354 |
| - use std::io::BufReader; |
355 |
| - use zkm_emulator::utils::get_block_path; |
356 |
| - |
357 |
| - #[test] |
358 |
| - fn load_and_check_mips_elf() { |
359 |
| - env_logger::try_init().unwrap_or_default(); |
360 |
| - let mut reader = BufReader::new(File::open("../emulator/test-vectors/hello").unwrap()); |
361 |
| - let mut buffer = Vec::new(); |
362 |
| - reader.read_to_end(&mut buffer).unwrap(); |
363 |
| - let max_mem = 0x80000000; |
364 |
| - let mut p: Program = Program::load_elf(&buffer, max_mem).unwrap(); |
365 |
| - log::info!("entry: {}", p.entry); |
366 |
| - |
367 |
| - let real_blockpath = get_block_path("../emulator/test-vectors", "13284491", "input"); |
368 |
| - log::info!("real block path: {}", real_blockpath); |
369 |
| - p.load_block(&real_blockpath).unwrap(); |
370 |
| - |
371 |
| - p.image.iter().for_each(|(k, v)| { |
372 |
| - if *k > INIT_SP && *k < INIT_SP + 50 { |
373 |
| - log::debug!("{:X}: {:X}", k, v.to_be()); |
374 |
| - } |
375 |
| - |
376 |
| - if *k > 0x30000000 && *k < 0x30000020 { |
377 |
| - log::debug!("{:X}: {:X}", k, v.to_be()); |
378 |
| - } |
379 |
| - }) |
380 |
| - } |
381 |
| -} |
0 commit comments