sim-se: add calls for network transmissions
Add recvfrom, sendto, recvmsg, and sendmsg system calls. Change-Id: I2eb50ea7823c8af57d99b3b8d443d2099418c06c Reviewed-on: https://gem5-review.googlesource.com/c/12114 Reviewed-by: Anthony Gutierrez <anthony.gutierrez@amd.com> Maintainer: Anthony Gutierrez <anthony.gutierrez@amd.com>
This commit is contained in:
committed by
Anthony Gutierrez
parent
a2ed7d5575
commit
c4e67f6837
@@ -266,10 +266,10 @@ static SyscallDesc syscallDescs64[] = {
|
||||
/* 41 */ SyscallDesc("socket", socketFunc<X86Linux64>),
|
||||
/* 42 */ SyscallDesc("connect", connectFunc),
|
||||
/* 43 */ SyscallDesc("accept", unimplementedFunc),
|
||||
/* 44 */ SyscallDesc("sendto", unimplementedFunc),
|
||||
/* 45 */ SyscallDesc("recvfrom", unimplementedFunc),
|
||||
/* 46 */ SyscallDesc("sendmsg", unimplementedFunc),
|
||||
/* 47 */ SyscallDesc("recvmsg", unimplementedFunc),
|
||||
/* 44 */ SyscallDesc("sendto", sendtoFunc),
|
||||
/* 45 */ SyscallDesc("recvfrom", recvfromFunc),
|
||||
/* 46 */ SyscallDesc("sendmsg", sendmsgFunc),
|
||||
/* 47 */ SyscallDesc("recvmsg", recvmsgFunc),
|
||||
/* 48 */ SyscallDesc("shutdown", shutdownFunc),
|
||||
/* 49 */ SyscallDesc("bind", bindFunc),
|
||||
/* 50 */ SyscallDesc("listen", listenFunc),
|
||||
|
||||
@@ -1304,3 +1304,313 @@ connectFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
|
||||
|
||||
return (status == -1) ? -errno : status;
|
||||
}
|
||||
|
||||
SyscallReturn
|
||||
recvfromFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
int tgt_fd = p->getSyscallArg(tc, index);
|
||||
Addr bufrPtr = p->getSyscallArg(tc, index);
|
||||
size_t bufrLen = p->getSyscallArg(tc, index);
|
||||
int flags = p->getSyscallArg(tc, index);
|
||||
Addr addrPtr = p->getSyscallArg(tc, index);
|
||||
Addr addrlenPtr = p->getSyscallArg(tc, index);
|
||||
|
||||
auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
|
||||
if (!sfdp)
|
||||
return -EBADF;
|
||||
int sim_fd = sfdp->getSimFD();
|
||||
|
||||
// Reserve buffer space.
|
||||
BufferArg bufrBuf(bufrPtr, bufrLen);
|
||||
|
||||
// Get address length.
|
||||
socklen_t addrLen = 0;
|
||||
if (addrlenPtr != 0) {
|
||||
// Read address length parameter.
|
||||
BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t));
|
||||
addrlenBuf.copyIn(tc->getMemProxy());
|
||||
addrLen = *((socklen_t *)addrlenBuf.bufferPtr());
|
||||
}
|
||||
|
||||
struct sockaddr sa, *sap = NULL;
|
||||
if (addrLen != 0) {
|
||||
BufferArg addrBuf(addrPtr, addrLen);
|
||||
addrBuf.copyIn(tc->getMemProxy());
|
||||
memcpy(&sa, (struct sockaddr *)addrBuf.bufferPtr(),
|
||||
sizeof(struct sockaddr));
|
||||
sap = &sa;
|
||||
}
|
||||
|
||||
ssize_t recvd_size = recvfrom(sim_fd,
|
||||
(void *)bufrBuf.bufferPtr(),
|
||||
bufrLen, flags, sap, (socklen_t *)&addrLen);
|
||||
|
||||
if (recvd_size == -1)
|
||||
return -errno;
|
||||
|
||||
// Pass the received data out.
|
||||
bufrBuf.copyOut(tc->getMemProxy());
|
||||
|
||||
// Copy address to addrPtr and pass it on.
|
||||
if (sap != NULL) {
|
||||
BufferArg addrBuf(addrPtr, addrLen);
|
||||
memcpy(addrBuf.bufferPtr(), sap, sizeof(sa));
|
||||
addrBuf.copyOut(tc->getMemProxy());
|
||||
}
|
||||
|
||||
// Copy len to addrlenPtr and pass it on.
|
||||
if (addrLen != 0) {
|
||||
BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t));
|
||||
*(socklen_t *)addrlenBuf.bufferPtr() = addrLen;
|
||||
addrlenBuf.copyOut(tc->getMemProxy());
|
||||
}
|
||||
|
||||
return recvd_size;
|
||||
}
|
||||
|
||||
SyscallReturn
|
||||
sendtoFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
int tgt_fd = p->getSyscallArg(tc, index);
|
||||
Addr bufrPtr = p->getSyscallArg(tc, index);
|
||||
size_t bufrLen = p->getSyscallArg(tc, index);
|
||||
int flags = p->getSyscallArg(tc, index);
|
||||
Addr addrPtr = p->getSyscallArg(tc, index);
|
||||
socklen_t addrLen = p->getSyscallArg(tc, index);
|
||||
|
||||
auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
|
||||
if (!sfdp)
|
||||
return -EBADF;
|
||||
int sim_fd = sfdp->getSimFD();
|
||||
|
||||
// Reserve buffer space.
|
||||
BufferArg bufrBuf(bufrPtr, bufrLen);
|
||||
bufrBuf.copyIn(tc->getMemProxy());
|
||||
|
||||
struct sockaddr sa, *sap = nullptr;
|
||||
memset(&sa, 0, sizeof(sockaddr));
|
||||
if (addrLen != 0) {
|
||||
BufferArg addrBuf(addrPtr, addrLen);
|
||||
addrBuf.copyIn(tc->getMemProxy());
|
||||
memcpy(&sa, (sockaddr*)addrBuf.bufferPtr(), addrLen);
|
||||
sap = &sa;
|
||||
}
|
||||
|
||||
ssize_t sent_size = sendto(sim_fd,
|
||||
(void *)bufrBuf.bufferPtr(),
|
||||
bufrLen, flags, sap, (socklen_t)addrLen);
|
||||
|
||||
return (sent_size == -1) ? -errno : sent_size;
|
||||
}
|
||||
|
||||
SyscallReturn
|
||||
recvmsgFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
int tgt_fd = p->getSyscallArg(tc, index);
|
||||
Addr msgPtr = p->getSyscallArg(tc, index);
|
||||
int flags = p->getSyscallArg(tc, index);
|
||||
|
||||
auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
|
||||
if (!sfdp)
|
||||
return -EBADF;
|
||||
int sim_fd = sfdp->getSimFD();
|
||||
|
||||
/**
|
||||
* struct msghdr {
|
||||
* void *msg_name; // optional address
|
||||
* socklen_t msg_namelen; // size of address
|
||||
* struct iovec *msg_iov; // iovec array
|
||||
* size_t msg_iovlen; // number entries in msg_iov
|
||||
* i // entries correspond to buffer
|
||||
* void *msg_control; // ancillary data
|
||||
* size_t msg_controllen; // ancillary data buffer len
|
||||
* int msg_flags; // flags on received message
|
||||
* };
|
||||
*
|
||||
* struct iovec {
|
||||
* void *iov_base; // starting address
|
||||
* size_t iov_len; // number of bytes to transfer
|
||||
* };
|
||||
*/
|
||||
|
||||
/**
|
||||
* The plan with this system call is to replace all of the pointers in the
|
||||
* structure and the substructure with BufferArg class pointers. We will
|
||||
* copy every field from the structures into our BufferArg classes.
|
||||
*/
|
||||
BufferArg msgBuf(msgPtr, sizeof(struct msghdr));
|
||||
msgBuf.copyIn(tc->getMemProxy());
|
||||
struct msghdr *msgHdr = (struct msghdr *)msgBuf.bufferPtr();
|
||||
|
||||
/**
|
||||
* We will use these address place holders to retain the pointers which
|
||||
* we are going to replace with our own buffers in our simulator address
|
||||
* space.
|
||||
*/
|
||||
Addr msg_name_phold = 0;
|
||||
Addr msg_iov_phold = 0;
|
||||
Addr iovec_base_phold[msgHdr->msg_iovlen];
|
||||
Addr msg_control_phold = 0;
|
||||
|
||||
/**
|
||||
* Record msg_name pointer then replace with buffer pointer.
|
||||
*/
|
||||
BufferArg *nameBuf = NULL;
|
||||
if (msgHdr->msg_name) {
|
||||
/*1*/msg_name_phold = (Addr)msgHdr->msg_name;
|
||||
/*2*/nameBuf = new BufferArg(msg_name_phold, msgHdr->msg_namelen);
|
||||
/*3*/nameBuf->copyIn(tc->getMemProxy());
|
||||
/*4*/msgHdr->msg_name = nameBuf->bufferPtr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Record msg_iov pointer then replace with buffer pointer. Also, setup
|
||||
* an array of buffer pointers for the iovec structs record and replace
|
||||
* their pointers with buffer pointers.
|
||||
*/
|
||||
BufferArg *iovBuf = NULL;
|
||||
BufferArg *iovecBuf[msgHdr->msg_iovlen];
|
||||
for (int i = 0; i < msgHdr->msg_iovlen; i++) {
|
||||
iovec_base_phold[i] = 0;
|
||||
iovecBuf[i] = NULL;
|
||||
}
|
||||
|
||||
if (msgHdr->msg_iov) {
|
||||
/*1*/msg_iov_phold = (Addr)msgHdr->msg_iov;
|
||||
/*2*/iovBuf = new BufferArg(msg_iov_phold, msgHdr->msg_iovlen *
|
||||
sizeof(struct iovec));
|
||||
/*3*/iovBuf->copyIn(tc->getMemProxy());
|
||||
for (int i = 0; i < msgHdr->msg_iovlen; i++) {
|
||||
if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) {
|
||||
/*1*/iovec_base_phold[i] =
|
||||
(Addr)((struct iovec *)iovBuf->bufferPtr())[i].iov_base;
|
||||
/*2*/iovecBuf[i] = new BufferArg(iovec_base_phold[i],
|
||||
((struct iovec *)iovBuf->bufferPtr())[i].iov_len);
|
||||
/*3*/iovecBuf[i]->copyIn(tc->getMemProxy());
|
||||
/*4*/((struct iovec *)iovBuf->bufferPtr())[i].iov_base =
|
||||
iovecBuf[i]->bufferPtr();
|
||||
}
|
||||
}
|
||||
/*4*/msgHdr->msg_iov = (struct iovec *)iovBuf->bufferPtr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Record msg_control pointer then replace with buffer pointer.
|
||||
*/
|
||||
BufferArg *controlBuf = NULL;
|
||||
if (msgHdr->msg_control) {
|
||||
/*1*/msg_control_phold = (Addr)msgHdr->msg_control;
|
||||
/*2*/controlBuf = new BufferArg(msg_control_phold,
|
||||
CMSG_ALIGN(msgHdr->msg_controllen));
|
||||
/*3*/controlBuf->copyIn(tc->getMemProxy());
|
||||
/*4*/msgHdr->msg_control = controlBuf->bufferPtr();
|
||||
}
|
||||
|
||||
ssize_t recvd_size = recvmsg(sim_fd, msgHdr, flags);
|
||||
|
||||
if (recvd_size < 0)
|
||||
return -errno;
|
||||
|
||||
if (msgHdr->msg_name) {
|
||||
nameBuf->copyOut(tc->getMemProxy());
|
||||
delete(nameBuf);
|
||||
msgHdr->msg_name = (void *)msg_name_phold;
|
||||
}
|
||||
|
||||
if (msgHdr->msg_iov) {
|
||||
for (int i = 0; i< msgHdr->msg_iovlen; i++) {
|
||||
if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) {
|
||||
iovecBuf[i]->copyOut(tc->getMemProxy());
|
||||
delete iovecBuf[i];
|
||||
((struct iovec *)iovBuf->bufferPtr())[i].iov_base =
|
||||
(void *)iovec_base_phold[i];
|
||||
}
|
||||
}
|
||||
iovBuf->copyOut(tc->getMemProxy());
|
||||
delete iovBuf;
|
||||
msgHdr->msg_iov = (struct iovec *)msg_iov_phold;
|
||||
}
|
||||
|
||||
if (msgHdr->msg_control) {
|
||||
controlBuf->copyOut(tc->getMemProxy());
|
||||
delete(controlBuf);
|
||||
msgHdr->msg_control = (void *)msg_control_phold;
|
||||
}
|
||||
|
||||
msgBuf.copyOut(tc->getMemProxy());
|
||||
|
||||
return recvd_size;
|
||||
}
|
||||
|
||||
SyscallReturn
|
||||
sendmsgFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
|
||||
{
|
||||
int index = 0;
|
||||
int tgt_fd = p->getSyscallArg(tc, index);
|
||||
Addr msgPtr = p->getSyscallArg(tc, index);
|
||||
int flags = p->getSyscallArg(tc, index);
|
||||
|
||||
auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
|
||||
if (!sfdp)
|
||||
return -EBADF;
|
||||
int sim_fd = sfdp->getSimFD();
|
||||
|
||||
/**
|
||||
* Reserve buffer space.
|
||||
*/
|
||||
BufferArg msgBuf(msgPtr, sizeof(struct msghdr));
|
||||
msgBuf.copyIn(tc->getMemProxy());
|
||||
struct msghdr msgHdr = *((struct msghdr *)msgBuf.bufferPtr());
|
||||
|
||||
/**
|
||||
* Assuming msgHdr.msg_iovlen >= 1, then there is no point calling
|
||||
* recvmsg without a buffer.
|
||||
*/
|
||||
struct iovec *iovPtr = msgHdr.msg_iov;
|
||||
BufferArg iovBuf((Addr)iovPtr, sizeof(struct iovec) * msgHdr.msg_iovlen);
|
||||
iovBuf.copyIn(tc->getMemProxy());
|
||||
struct iovec *iov = (struct iovec *)iovBuf.bufferPtr();
|
||||
msgHdr.msg_iov = iov;
|
||||
|
||||
/**
|
||||
* Cannot instantiate buffers till inside the loop.
|
||||
* Create array to hold buffer addresses, to be used during copyIn of
|
||||
* send data.
|
||||
*/
|
||||
BufferArg **bufferArray = (BufferArg **)malloc(msgHdr.msg_iovlen
|
||||
* sizeof(BufferArg *));
|
||||
|
||||
/**
|
||||
* Iterate through the iovec structures:
|
||||
* Get the base buffer addreses, reserve iov_len amount of space for each.
|
||||
* Put the buf address into the bufferArray for later retrieval.
|
||||
*/
|
||||
for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) {
|
||||
Addr basePtr = (Addr) iov[iovIndex].iov_base;
|
||||
bufferArray[iovIndex] = new BufferArg(basePtr, iov[iovIndex].iov_len);
|
||||
bufferArray[iovIndex]->copyIn(tc->getMemProxy());
|
||||
iov[iovIndex].iov_base = bufferArray[iovIndex]->bufferPtr();
|
||||
}
|
||||
|
||||
ssize_t sent_size = sendmsg(sim_fd, &msgHdr, flags);
|
||||
int local_errno = errno;
|
||||
|
||||
/**
|
||||
* Free dynamically allocated memory.
|
||||
*/
|
||||
for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) {
|
||||
BufferArg *baseBuf = ( BufferArg *)bufferArray[iovIndex];
|
||||
delete(baseBuf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Malloced above.
|
||||
*/
|
||||
free(bufferArray);
|
||||
|
||||
return (sent_size < 0) ? -local_errno : sent_size;
|
||||
}
|
||||
|
||||
|
||||
@@ -332,6 +332,22 @@ SyscallReturn getdents64Func(SyscallDesc *desc, int num,
|
||||
Process *p, ThreadContext *tc);
|
||||
#endif
|
||||
|
||||
// Target sendto() handler.
|
||||
SyscallReturn sendtoFunc(SyscallDesc *desc, int num,
|
||||
Process *p, ThreadContext *tc);
|
||||
|
||||
// Target recvfrom() handler.
|
||||
SyscallReturn recvfromFunc(SyscallDesc *desc, int num,
|
||||
Process *p, ThreadContext *tc);
|
||||
|
||||
// Target recvmsg() handler.
|
||||
SyscallReturn recvmsgFunc(SyscallDesc *desc, int num,
|
||||
Process *p, ThreadContext *tc);
|
||||
|
||||
// Target sendmsg() handler.
|
||||
SyscallReturn sendmsgFunc(SyscallDesc *desc, int num,
|
||||
Process *p, ThreadContext *tc);
|
||||
|
||||
// Target getuid() handler.
|
||||
SyscallReturn getuidFunc(SyscallDesc *desc, int num,
|
||||
Process *p, ThreadContext *tc);
|
||||
|
||||
Reference in New Issue
Block a user