ipmi: allow pass more than single buffer to fake client invoke

This commit is contained in:
DH 2024-09-26 23:56:49 +03:00
parent 66ff7a3000
commit 8120002816

View File

@ -33,6 +33,7 @@
#include <pthread.h> #include <pthread.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/prctl.h> #include <sys/prctl.h>
#include <tuple>
#include <ucontext.h> #include <ucontext.h>
#include <atomic> #include <atomic>
@ -1613,9 +1614,13 @@ template <typename T = std::byte> struct GuestAlloc {
orbis::ptr<T> guestAddress; orbis::ptr<T> guestAddress;
GuestAlloc(std::size_t size) { GuestAlloc(std::size_t size) {
guestAddress = orbis::ptr<T>(rx::vm::map( if (size == 0) {
nullptr, size, rx::vm::kMapProtCpuRead | rx::vm::kMapProtCpuWrite, guestAddress = nullptr;
rx::vm::kMapFlagPrivate | rx::vm::kMapFlagAnonymous)); } else {
guestAddress = orbis::ptr<T>(rx::vm::map(
nullptr, size, rx::vm::kMapProtCpuRead | rx::vm::kMapProtCpuWrite,
rx::vm::kMapFlagPrivate | rx::vm::kMapFlagAnonymous));
}
} }
GuestAlloc() : GuestAlloc(sizeof(T)) {} GuestAlloc() : GuestAlloc(sizeof(T)) {}
@ -1632,7 +1637,20 @@ template <typename T = std::byte> struct GuestAlloc {
} }
} }
~GuestAlloc() { rx::vm::unmap(guestAddress, sizeof(T)); } GuestAlloc(const GuestAlloc &) = delete;
GuestAlloc(GuestAlloc &&other) : guestAddress(other.guestAddress) {
other.guestAddress = 0;
}
GuestAlloc &operator=(GuestAlloc &&other) {
std::swap(guestAddress, other.guestAddress);
}
~GuestAlloc() {
if (guestAddress != 0) {
rx::vm::unmap(guestAddress, sizeof(T));
}
}
operator orbis::ptr<T>() { return guestAddress; } operator orbis::ptr<T>() { return guestAddress; }
T *operator->() { return guestAddress; } T *operator->() { return guestAddress; }
@ -1644,28 +1662,41 @@ struct IpmiClient {
orbis::uint kid; orbis::uint kid;
orbis::Thread *thread; orbis::Thread *thread;
orbis::sint sendSyncMessage(std::uint32_t method, const void *data, orbis::sint
std::size_t size, sendSyncMessageRaw(std::uint32_t method,
std::vector<std::byte> &outData) { const std::vector<std::vector<std::byte>> &inData,
std::vector<std::vector<std::byte>> &outBuf) {
GuestAlloc<orbis::sint> serverResult; GuestAlloc<orbis::sint> serverResult;
GuestAlloc outBufferInfo = orbis::IpmiBufferInfo{ GuestAlloc<orbis::IpmiDataInfo> guestInDataArray{
.data = outData.data(), sizeof(orbis::IpmiDataInfo) * inData.size()};
.capacity = outData.size(), GuestAlloc<orbis::IpmiBufferInfo> guestOutBufArray{
}; sizeof(orbis::IpmiBufferInfo) * outBuf.size()};
auto guestData = GuestAlloc{data, size}; std::vector<GuestAlloc<std::byte>> guestAllocs;
guestAllocs.reserve(inData.size() + outBuf.size());
GuestAlloc inDataInfo = orbis::IpmiDataInfo{ for (auto &data : inData) {
.data = guestData, auto pointer =
.size = size, guestAllocs.emplace_back(data.data(), data.size()).guestAddress;
};
guestInDataArray.guestAddress[&data - inData.data()] = {
.data = pointer, .size = data.size()};
}
for (auto &buf : outBuf) {
auto pointer =
guestAllocs.emplace_back(buf.data(), buf.size()).guestAddress;
guestOutBufArray.guestAddress[&buf - outBuf.data()] = {
.data = pointer, .capacity = buf.size()};
}
GuestAlloc params = orbis::IpmiSyncCallParams{ GuestAlloc params = orbis::IpmiSyncCallParams{
.method = method, .method = method,
.numInData = 1, .numInData = static_cast<orbis::uint32_t>(inData.size()),
.numOutData = 1, .numOutData = static_cast<orbis::uint32_t>(outBuf.size()),
.pInData = inDataInfo, .pInData = guestInDataArray,
.pOutData = outBufferInfo, .pOutData = guestOutBufArray,
.pResult = serverResult, .pResult = serverResult,
}; };
@ -1673,29 +1704,34 @@ struct IpmiClient {
orbis::sysIpmiClientInvokeSyncMethod(thread, errorCode, kid, params, orbis::sysIpmiClientInvokeSyncMethod(thread, errorCode, kid, params,
sizeof(orbis::IpmiSyncCallParams)); sizeof(orbis::IpmiSyncCallParams));
outData.resize(outBufferInfo->size); for (auto &buf : outBuf) {
auto size = guestOutBufArray.guestAddress[inData.data() - &buf].size;
buf.resize(size);
}
return serverResult; return serverResult;
} }
template <typename T> template <typename... InputTypes>
orbis::sint sendSyncMessage(std::uint32_t method, const T &data, orbis::sint sendSyncMessage(std::uint32_t method,
std::vector<std::byte> &outData) { const InputTypes &...input) {
return sendSyncMessage(method, &data, sizeof(data), outData); std::vector<std::vector<std::byte>> outBuf;
return sendSyncMessageRaw(method, {toBytes(input)...}, outBuf);
} }
template <typename T> template <typename... OutputTypes, typename... InputTypes>
orbis::sint sendSyncMessage(std::uint32_t method, const T &data) { requires((sizeof...(OutputTypes) > 0) || sizeof...(InputTypes) == 0)
std::vector<std::byte> outData; std::tuple<OutputTypes...> sendSyncMessage(std::uint32_t method,
return sendSyncMessage(method, &data, sizeof(data), outData); InputTypes... input) {
} std::vector<std::vector<std::byte>> outBuf{sizeof(OutputTypes)...};
sendSyncMessageRaw(method, {toBytes(input)...}, outBuf);
std::tuple<OutputTypes...> output;
template <typename T> auto unpack = [&]<std::size_t... I>(std::index_sequence<I...>) {
std::vector<std::byte> sendSyncMessage(std::uint32_t method, const T &data, ((std::get<I>(output) = *reinterpret_cast<OutputTypes *>(outBuf.data())),
std::size_t outputCapacity) { ...);
std::vector<std::byte> outData; };
outData.resize(outputCapacity); unpack(std::make_index_sequence<sizeof...(OutputTypes)>{});
sendSyncMessage(method, &data, sizeof(data), outData); return output;
return outData;
} }
}; };