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();
90 if (thread_.joinable()) thread_.join();
96void rps::SrpV3Emulation::runThread() {
98 log_->debug(
"Worker thread started");
102 std::unique_lock<std::mutex> lock(queMtx_);
103 queCond_.wait(lock, [
this] {
return !queue_.empty() || !threadEn_; });
105 if (!threadEn_)
break;
107 frame = queue_.front();
114 log_->debug(
"Worker thread stopped");
118uint8_t* rps::SrpV3Emulation::allocatePage(uint64_t addr4k) {
119 uint8_t* page =
reinterpret_cast<uint8_t*
>(malloc(0x1000));
120 if (page ==
nullptr) {
121 log_->error(
"Failed to allocate page at 0x%" PRIx64, addr4k);
126 std::mt19937 gen(std::random_device {}());
127 uint32_t* p32 =
reinterpret_cast<uint32_t*
>(page);
128 for (
size_t i = 0; i < 0x1000 / 4; i++) p32[i] = gen();
130 memMap_.insert(std::make_pair(addr4k, page));
132 log_->debug(
"Allocating page at 0x%" PRIx64
". Total pages %" PRIu32, addr4k, totAlloc_);
137void rps::SrpV3Emulation::readMemory(uint64_t address, uint8_t* data, uint32_t size) {
143 addr4k = (address / 0x1000) * 0x1000;
144 off4k = address % 0x1000;
145 size4k = (addr4k + 0x1000) - (addr4k + off4k);
147 if (size4k > size) size4k = size;
149 auto it = memMap_.find(addr4k);
150 if (it == memMap_.end()) {
152 uint8_t* page = allocatePage(addr4k);
153 if (page ==
nullptr)
return;
154 memcpy(data, page + off4k, size4k);
156 memcpy(data, it->second + off4k, size4k);
166void rps::SrpV3Emulation::writeMemory(uint64_t address,
const uint8_t* data, uint32_t size) {
172 addr4k = (address / 0x1000) * 0x1000;
173 off4k = address % 0x1000;
174 size4k = (addr4k + 0x1000) - (addr4k + off4k);
176 if (size4k > size) size4k = size;
178 auto it = memMap_.find(addr4k);
179 if (it == memMap_.end()) {
180 uint8_t* page = allocatePage(addr4k);
181 if (page ==
nullptr)
return;
182 it = memMap_.find(addr4k);
185 memcpy(it->second + off4k, data, size4k);
196 std::lock_guard<std::mutex> lock(queMtx_);
199 queCond_.notify_one();
204 uint32_t header[HeadLen / 4];
205 uint32_t tail[TailLen / 4];
217 if (frame->getError()) {
218 log_->warning(
"Got errored frame = 0x%" PRIx8, frame->getError());
223 fSize = frame->getPayload();
224 if (fSize < HeadLen) {
225 log_->warning(
"Got undersized frame size = %" PRIu32, fSize);
234 if ((header[0] & 0xFF) != 0x03) {
235 log_->warning(
"Got non-SRPv3 frame, version = 0x%" PRIx32, header[0] & 0xFF);
240 opCode = (header[0] >> 8) & 0x3;
242 address = (
static_cast<uint64_t
>(header[3]) << 32) | header[2];
243 reqSize = header[4] + 1;
247 log_->warning(
"Got invalid SRPv3 opcode 0x3 for id=%" PRIu32,
id);
253 if (reqSize < 4 || reqSize > 4096 || (reqSize & 0x3) != 0) {
254 log_->warning(
"Got invalid SRPv3 request size=%" PRIu32
" for id=%" PRIu32, reqSize,
id);
258 doWrite = (opCode == 0x1);
259 isPost = (opCode == 0x2);
261 log_->debug(
"Got request id=%" PRIu32
", opCode=%" PRIu32
", addr=0x%" PRIx64
", size=%" PRIu32,
271 std::lock_guard<std::mutex> lock(memMtx_);
273 if (doWrite || isPost) {
275 if (fSize < HeadLen + reqSize) {
276 log_->warning(
"Write frame too small: got %" PRIu32
", need %" PRIu32, fSize, HeadLen + reqSize);
281 frLock = frame->lock();
282 fIter = frame->begin() + HeadLen;
283 std::vector<uint8_t> wrData(reqSize);
287 writeMemory(address, wrData.data(), reqSize);
289 log_->debug(
"Write complete id=%" PRIu32
", addr=0x%" PRIx64
", size=%" PRIu32,
id, address, reqSize);
296 uint32_t respLen = HeadLen + reqSize + TailLen;
298 respFrame->setPayload(respLen);
305 std::vector<uint8_t> rdData(reqSize);
306 readMemory(address, rdData.data(), reqSize);
313 log_->debug(
"Sending response id=%" PRIu32
", size=%" PRIu32,
id, respLen);
315 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