1 #include "lua/internal.hpp"
2 #include "lua/debug.hpp"
3 #include "core/memorymanip.hpp"
4 #include "core/memorywatch.hpp"
5 #include "core/instance.hpp"
6 #include "core/moviedata.hpp"
7 #include "core/moviefile.hpp"
8 #include "core/rom.hpp"
9 #include "library/sha256.hpp"
10 #include "library/skein.hpp"
11 #include "library/string.hpp"
12 #include "library/serialization.hpp"
13 #include "library/memoryspace.hpp"
14 #include "library/minmax.hpp"
15 #include "library/int24.hpp"
19 int handle_push_vma(lua::state
& L
, memory_space::region
& r
)
23 L
.pushlstring(r
.name
.c_str(), r
.name
.size());
25 L
.pushstring("address");
32 L
.pushnumber(r
.last_address());
34 L
.pushstring("readonly");
35 L
.pushboolean(r
.readonly
);
37 L
.pushstring("special");
38 L
.pushboolean(r
.special
);
40 L
.pushstring("endian");
41 L
.pushnumber(r
.endian
);
46 template<typename T
> T
bswap(T val
)
49 serialization::swap_endian(val2
);
56 lua_vma(lua::state
& L
, memory_space::region
* r
);
57 static size_t overcommit(memory_space::region
* r
) { return 0; }
58 int info(lua::state
& L
, lua::parameters
& P
);
59 template<class T
, bool _bswap
> int rw(lua::state
& L
, lua::parameters
& P
);
60 template<bool write
, bool sign
> int scattergather(lua::state
& L
, lua::parameters
& P
);
61 template<class T
> int hash(lua::state
& L
, lua::parameters
& P
);
62 template<bool cmp
> int storecmp(lua::state
& L
, lua::parameters
& P
);
63 int readregion(lua::state
& L
, lua::parameters
& P
);
64 int writeregion(lua::state
& L
, lua::parameters
& P
);
65 int cheat(lua::state
& L
, lua::parameters
& P
);
66 template<debug_context::etype type
, bool reg
> int registerX(lua::state
& L
, lua::parameters
& P
);
81 lua_vma_list(lua::state
& L
);
82 static size_t overcommit() { return 0; }
83 static int create(lua::state
& L
, lua::parameters
& P
);
84 int index(lua::state
& L
, lua::parameters
& P
);
85 int newindex(lua::state
& L
, lua::parameters
& P
);
86 int call(lua::state
& L
, lua::parameters
& P
);
95 static sha256
create()
99 static void write(sha256
& h
, void* b
, size_t s
)
101 h
.write(reinterpret_cast<uint8_t*>(b
), s
);
103 static std::string
read(sha256
& h
)
111 static skein::hash
create()
113 return skein::hash(skein::hash::PIPE_512
, 256);
115 static void write(skein::hash
& h
, void* b
, size_t s
)
117 h
.write(reinterpret_cast<uint8_t*>(b
), s
);
119 static std::string
read(skein::hash
& h
)
123 return hex::b_to(buf
, 32);
127 lua::_class
<lua_vma
> LUA_class_vma(lua_class_memory
, "VMA", {}, {
128 {"info", &lua_vma::info
},
129 {"read", &lua_vma::scattergather
<false, false>},
130 {"sread", &lua_vma::scattergather
<false, true>},
131 {"write", &lua_vma::scattergather
<true, false>},
132 {"sbyte", &lua_vma::rw
<int8_t, false>},
133 {"byte", &lua_vma::rw
<uint8_t, false>},
134 {"sword", &lua_vma::rw
<int16_t, false>},
135 {"word", &lua_vma::rw
<uint16_t, false>},
136 {"shword", &lua_vma::rw
<ss_int24_t
, false>},
137 {"hword", &lua_vma::rw
<ss_uint24_t
, false>},
138 {"sdword", &lua_vma::rw
<int32_t, false>},
139 {"dword", &lua_vma::rw
<uint32_t, false>},
140 {"sqword", &lua_vma::rw
<int64_t, false>},
141 {"qword", &lua_vma::rw
<uint64_t, false>},
142 {"float", &lua_vma::rw
<float, false>},
143 {"double", &lua_vma::rw
<double, false>},
144 {"isbyte", &lua_vma::rw
<int8_t, true>},
145 {"ibyte", &lua_vma::rw
<uint8_t, true>},
146 {"isword", &lua_vma::rw
<int16_t, true>},
147 {"iword", &lua_vma::rw
<uint16_t, true>},
148 {"ishword", &lua_vma::rw
<ss_int24_t
, true>},
149 {"ihword", &lua_vma::rw
<ss_uint24_t
, true>},
150 {"isdword", &lua_vma::rw
<int32_t, true>},
151 {"idword", &lua_vma::rw
<uint32_t, true>},
152 {"isqword", &lua_vma::rw
<int64_t, true>},
153 {"iqword", &lua_vma::rw
<uint64_t, true>},
154 {"ifloat", &lua_vma::rw
<float, true>},
155 {"idouble", &lua_vma::rw
<double, true>},
156 {"cheat", &lua_vma::cheat
},
157 {"sha256", &lua_vma::hash
<l_sha256_h
>},
158 {"skein", &lua_vma::hash
<l_skein_h
>},
159 {"store", &lua_vma::storecmp
<false>},
160 {"storecmp", &lua_vma::storecmp
<true>},
161 {"readregion", &lua_vma::readregion
},
162 {"writeregion", &lua_vma::writeregion
},
163 {"registerread", &lua_vma::registerX
<debug_context::DEBUG_READ
, true>},
164 {"unregisterread", &lua_vma::registerX
<debug_context::DEBUG_READ
, false>},
165 {"registerwrite", &lua_vma::registerX
<debug_context::DEBUG_WRITE
, true>},
166 {"unregisterwrite", &lua_vma::registerX
<debug_context::DEBUG_WRITE
, false>},
167 {"registerexec", &lua_vma::registerX
<debug_context::DEBUG_EXEC
, true>},
168 {"unregisterexec", &lua_vma::registerX
<debug_context::DEBUG_EXEC
, false>},
171 lua::_class
<lua_vma_list
> LUA_class_vmalist(lua_class_memory
, "VMALIST", {
172 {"new", lua_vma_list::create
},
174 {"__index", &lua_vma_list::index
},
175 {"__newindex", &lua_vma_list::newindex
},
176 {"__call", &lua_vma_list::call
},
179 lua_vma::lua_vma(lua::state
& L
, memory_space::region
* r
)
187 int lua_vma::info(lua::state
& L
, lua::parameters
& P
)
189 for(auto i
: CORE().memory
->get_regions())
191 return handle_push_vma(L
, *i
);
192 (stringfmt() << P
.get_fname() << ": Stale region").throwex();
193 return 0; //NOTREACHED
196 template<class T
, bool _bswap
> int lua_vma::rw(lua::state
& L
, lua::parameters
& P
)
202 P(P
.skipped(), addr
);
204 if(addr
> vmasize
|| addr
> vmasize
- sizeof(T
))
205 throw std::runtime_error("VMA::rw<T>: Address outside VMA bounds");
208 T val
= core
.memory
->read
<T
>(addr
+ vmabase
);
209 if(_bswap
) val
= bswap(val
);
212 } else if(P
.is_number()) {
215 (stringfmt() << P
.get_fname() << ": VMA is read-only").throwex();
217 if(_bswap
) val
= bswap(val
);
218 core
.memory
->write
<T
>(addr
+ vmabase
, val
);
221 P
.expected("number or nil");
222 return 0; //NOTREACHED
225 template<bool write
, bool sign
> int lua_vma::scattergather(lua::state
& L
, lua::parameters
& P
)
236 while(!P
.is_novalue()) {
243 addr
= P
.arg
<uint64_t>();
245 core
.memory
->write
<uint8_t>(addr
+ vmabase
, val
>> shift
);
247 val
= val
+ ((uint64_t)core
.memory
->read
<uint8_t>(addr
+ vmabase
) << shift
);
252 if(val
>= (1ULL << (shift
- 1))) sval
-= (1ULL << shift
);
253 if(sign
) L
.pushnumber(sval
); else L
.pushnumber(val
);
255 return write
? 0 : 1;
258 template<class T
> int lua_vma::hash(lua::state
& L
, lua::parameters
& P
)
261 uint64_t addr
, size
, rows
, stride
= 0;
263 P(P
.skipped(), addr
, size
, P
.optional(rows
, 1));
264 if(rows
> 1) P(stride
);
266 //First verify that all reads are to the region.
267 if(!memoryspace_row_limited(addr
, size
, rows
, stride
, vmasize
))
268 throw std::runtime_error("Region out of range");
270 auto hstate
= T::create();
271 //Try to map the VMA.
272 char* vmabuf
= core
.memory
->get_physical_mapping(vmabase
, vmasize
);
274 for(uint64_t i
= 0; i
< rows
; i
++) {
275 T::write(hstate
, vmabuf
+ addr
, size
);
279 uint8_t buf
[512]; //Must be power of 2.
281 for(uint64_t i
= 0; i
< rows
; i
++) {
282 for(uint64_t j
= 0; j
< size
; j
++) {
283 buf
[bf
] = core
.memory
->read
<uint8_t>(vmabase
+ addr
+ j
);
284 bf
= (bf
+ 1) & (sizeof(buf
) - 1);
286 T::write(hstate
, buf
, sizeof(buf
));
291 T::write(hstate
, buf
, bf
);
293 L
.pushlstring(T::read(hstate
));
297 int lua_vma::readregion(lua::state
& L
, lua::parameters
& P
)
302 P(P
.skipped(), addr
, size
);
304 if(addr
>= vmasize
|| size
> vmasize
|| addr
+ size
> vmasize
)
305 throw std::runtime_error("Read out of range");
308 char* vmabuf
= core
.memory
->get_physical_mapping(vmabase
, vmasize
);
311 for(size_t i
= 0; i
< size
; i
++) {
313 L
.pushnumber(static_cast<unsigned char>(vmabuf
[addr
+ i
]));
318 for(size_t i
= 0; i
< size
; i
++) {
320 L
.pushnumber(core
.memory
->read
<uint8_t>(addr
+ i
));
327 int lua_vma::writeregion(lua::state
& L
, lua::parameters
& P
)
333 P(P
.skipped(), addr
, P
.table(ltbl
));
335 auto g
= core
.memory
->lookup(vmabase
);
336 if(!g
.first
|| g
.first
->readonly
)
337 throw std::runtime_error("Memory address is read-only");
339 throw std::runtime_error("Write out of range");
342 char* vmabuf
= core
.memory
->get_physical_mapping(vmabase
, vmasize
);
344 for(size_t i
= 0;; i
++) {
347 if(L
.type(-1) == LUA_TNIL
)
349 if(addr
+ i
>= vmasize
)
350 throw std::runtime_error("Write out of range");
351 vmabuf
[addr
+ i
] = L
.tointeger(-1);
355 for(size_t i
= 0;; i
++) {
358 if(L
.type(-1) == LUA_TNIL
)
360 if(addr
+ i
>= vmasize
)
361 throw std::runtime_error("Write out of range");
362 core
.memory
->write
<uint8_t>(vmabase
+ addr
+ i
, L
.tointeger(-1));
369 template<bool cmp
> int lua_vma::storecmp(lua::state
& L
, lua::parameters
& P
)
372 uint64_t addr
, daddr
, size
, rows
, stride
= 0;
375 P(P
.skipped(), addr
, daddr
, size
, P
.optional(rows
, 1));
376 if(rows
> 1) P(stride
);
378 //First verify that all reads are to the region.
379 if(!memoryspace_row_limited(addr
, size
, rows
, stride
, vmasize
))
380 throw std::runtime_error("Source out of range");
382 //Calculate new size of target.
383 auto& h
= core
.mlogic
->get_mfile().host_memory
;
384 size_t rsize
= size
* rows
;
385 if(size
&& rsize
/ size
!= rows
)
386 throw std::runtime_error("Copy size out of range");
387 if((size_t)daddr
+ rsize
< rsize
)
388 throw std::runtime_error("Target out of range");
389 if(daddr
+ rsize
> h
.size()) {
390 h
.resize(daddr
+ rsize
);
394 //Try to map the VMA.
395 char* vmabuf
= core
.memory
->get_physical_mapping(vmabase
, vmasize
);
397 for(uint64_t i
= 0; i
< rows
; i
++) {
398 bool eq
= (cmp
&& !memcmp(&h
[daddr
], vmabuf
+ addr
, size
));
400 memcpy(&h
[daddr
], vmabuf
+ addr
, size
);
406 for(uint64_t i
= 0; i
< rows
; i
++) {
407 for(uint64_t j
= 0; j
< size
; j
++) {
408 uint8_t byte
= core
.memory
->read
<uint8_t>(vmabase
+ addr
+ j
);
409 bool eq
= (cmp
&& ((uint8_t)h
[daddr
+ j
] == byte
));
417 if(cmp
) L
.pushboolean(equals
);
421 template<debug_context::etype type
, bool reg
> int lua_vma::registerX(lua::state
& L
, lua::parameters
& P
)
425 P(P
.skipped(), addr
, P
.function(lfn
));
428 handle_registerX
<type
>(L
, vmabase
+ addr
, lfn
);
432 handle_unregisterX
<type
>(L
, vmabase
+ addr
, lfn
);
437 int lua_vma::cheat(lua::state
& L
, lua::parameters
& P
)
440 uint64_t addr
, value
;
442 P(P
.skipped(), addr
);
444 throw std::runtime_error("Address out of range");
446 core
.dbg
->clear_cheat(vmabase
+ addr
);
449 core
.dbg
->set_cheat(vmabase
+ addr
, value
);
454 lua_vma_list::lua_vma_list(lua::state
& L
)
458 int lua_vma_list::create(lua::state
& L
, lua::parameters
& P
)
460 lua::_class
<lua_vma_list
>::create(L
);
464 int lua_vma_list::call(lua::state
& L
, lua::parameters
& P
)
468 for(auto i
: CORE().memory
->get_regions()) {
470 L
.pushlstring(i
->name
);
476 int lua_vma_list::index(lua::state
& L
, lua::parameters
& P
)
482 auto l
= CORE().memory
->get_regions();
484 std::list
<memory_space::region
*>::iterator i
;
485 for(i
= l
.begin(), j
= 0; i
!= l
.end(); i
++, j
++)
486 if((*i
)->name
== vma
) {
487 lua::_class
<lua_vma
>::create(L
, *i
);
490 (stringfmt() << P
.get_fname() << ": No such VMA").throwex();
491 return 0; //NOTREACHED
494 int lua_vma_list::newindex(lua::state
& L
, lua::parameters
& P
)
496 throw std::runtime_error("Writing is not allowed");