42 #include <boost/python.hpp>
43namespace bp = boost::python;
53void rps::SrpV3Emulation::setup_python() {
55 bp::class_<rps::SrpV3Emulation, rps::SrpV3EmulationPtr, bp::bases<ris::Master, ris::Slave>, boost::noncopyable>(
58 bp::implicitly_convertible<rps::SrpV3EmulationPtr, ris::MasterPtr>();
59 bp::implicitly_convertible<rps::SrpV3EmulationPtr, ris::SlavePtr>();
64rps::SrpV3Emulation::SrpV3Emulation() :
ris::Master(),
ris::Slave() {
68 thread_ = std::thread(&SrpV3Emulation::runThread,
this);
72rps::SrpV3Emulation::~SrpV3Emulation() {
75 MemoryMap::iterator it = memMap_.begin();
76 while (it != memMap_.end()) {
83void rps::SrpV3Emulation::stop() {
85 std::lock_guard<std::mutex> lock(queMtx_);
88 queCond_.notify_all();
93 if (thread_.joinable()) thread_.join();
100void rps::SrpV3Emulation::runThread() {
102 log_->debug(
"Worker thread started");
106 std::unique_lock<std::mutex> lock(queMtx_);
107 queCond_.wait(lock, [
this] {
return !queue_.empty() || !threadEn_; });
109 if (!threadEn_)
break;
111 frame = queue_.front();
118 log_->debug(
"Worker thread stopped");
122uint8_t* rps::SrpV3Emulation::allocatePage(uint64_t addr4k) {
123 uint8_t* page =
reinterpret_cast<uint8_t*
>(malloc(0x1000));
124 if (page ==
nullptr) {
125 log_->error(
"Failed to allocate page at 0x%" PRIx64, addr4k);
130 std::mt19937 gen(std::random_device {}());
131 uint32_t* p32 =
reinterpret_cast<uint32_t*
>(page);
132 for (
size_t i = 0; i < 0x1000 / 4; i++) p32[i] = gen();
134 memMap_.insert(std::make_pair(addr4k, page));
136 log_->debug(
"Allocating page at 0x%" PRIx64
". Total pages %" PRIu32, addr4k, totAlloc_);
141void rps::SrpV3Emulation::readMemory(uint64_t address, uint8_t* data, uint32_t size) {
147 addr4k = (address / 0x1000) * 0x1000;
148 off4k = address % 0x1000;
149 size4k = (addr4k + 0x1000) - (addr4k + off4k);
151 if (size4k > size) size4k = size;
153 auto it = memMap_.find(addr4k);
154 if (it == memMap_.end()) {
156 uint8_t* page = allocatePage(addr4k);
157 if (page ==
nullptr)
return;
158 memcpy(data, page + off4k, size4k);
160 memcpy(data, it->second + off4k, size4k);
170void rps::SrpV3Emulation::writeMemory(uint64_t address,
const uint8_t* data, uint32_t size) {
176 addr4k = (address / 0x1000) * 0x1000;
177 off4k = address % 0x1000;
178 size4k = (addr4k + 0x1000) - (addr4k + off4k);
180 if (size4k > size) size4k = size;
182 auto it = memMap_.find(addr4k);
183 if (it == memMap_.end()) {
184 uint8_t* page = allocatePage(addr4k);
185 if (page ==
nullptr)
return;
186 it = memMap_.find(addr4k);
189 memcpy(it->second + off4k, data, size4k);
200 std::lock_guard<std::mutex> lock(queMtx_);
203 queCond_.notify_one();
208 uint32_t header[HeadLen / 4];
209 uint32_t tail[TailLen / 4];
221 if (frame->getError()) {
222 log_->warning(
"Got errored frame = 0x%" PRIx8, frame->getError());
227 fSize = frame->getPayload();
228 if (fSize < HeadLen) {
229 log_->warning(
"Got undersized frame size = %" PRIu32, fSize);
238 if ((header[0] & 0xFF) != 0x03) {
239 log_->warning(
"Got non-SRPv3 frame, version = 0x%" PRIx32, header[0] & 0xFF);
244 opCode = (header[0] >> 8) & 0x3;
246 address = (
static_cast<uint64_t
>(header[3]) << 32) | header[2];
247 reqSize = header[4] + 1;
251 log_->warning(
"Got invalid SRPv3 opcode 0x3 for id=%" PRIu32,
id);
257 if (reqSize < 4 || reqSize > 4096 || (reqSize & 0x3) != 0) {
258 log_->warning(
"Got invalid SRPv3 request size=%" PRIu32
" for id=%" PRIu32, reqSize,
id);
262 doWrite = (opCode == 0x1);
263 isPost = (opCode == 0x2);
265 log_->debug(
"Got request id=%" PRIu32
", opCode=%" PRIu32
", addr=0x%" PRIx64
", size=%" PRIu32,
275 std::lock_guard<std::mutex> lock(memMtx_);
277 if (doWrite || isPost) {
279 if (fSize < HeadLen + reqSize) {
280 log_->warning(
"Write frame too small: got %" PRIu32
", need %" PRIu32, fSize, HeadLen + reqSize);
285 frLock = frame->lock();
286 fIter = frame->begin() + HeadLen;
287 std::vector<uint8_t> wrData(reqSize);
291 writeMemory(address, wrData.data(), reqSize);
293 log_->debug(
"Write complete id=%" PRIu32
", addr=0x%" PRIx64
", size=%" PRIu32,
id, address, reqSize);
300 uint32_t respLen = HeadLen + reqSize + TailLen;
302 respFrame->setPayload(respLen);
309 std::vector<uint8_t> rdData(reqSize);
310 readMemory(address, rdData.data(), reqSize);
317 log_->debug(
"Sending response id=%" PRIu32
", size=%" PRIu32,
id, respLen);
319 sendFrame(respFrame);
RAII helper that releases the Python GIL for a scope.
static std::shared_ptr< rogue::Logging > create(const std::string &name, bool quiet=false)
Creates a logger instance.
Random-access byte iterator across a Frame payload.
static void fromFrame(rogue::interfaces::stream::FrameIterator &iter, uint32_t size, void *dst)
Copies bytes from a frame iterator to a destination pointer.
std::shared_ptr< rogue::interfaces::stream::Frame > FramePtr
Shared pointer alias for Frame.
static void toFrame(rogue::interfaces::stream::FrameIterator &iter, uint32_t size, void *src)
Copies bytes from a source pointer into a frame iterator.
std::shared_ptr< rogue::interfaces::stream::FrameLock > FrameLockPtr
Shared pointer alias for FrameLock.
std::shared_ptr< rogue::protocols::srp::SrpV3Emulation > SrpV3EmulationPtr