Skip to content

Commit 5a63561

Browse files
authored
Merge pull request #836 from fjtrujy/fix/ps2ip-rpc-select-pkt-abi
fix: [ps2ip_rpc] explicit fixed-layout `select_pkt` across EE/IOP RPC
2 parents 0391dd8 + 6bbe6ff commit 5a63561

3 files changed

Lines changed: 99 additions & 34 deletions

File tree

common/include/ps2ip_rpc.h

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -132,21 +132,39 @@ typedef struct
132132
u8 buffer[128];
133133
} setsockopt_pkt;
134134

135+
/* On-the-wire fd_set for the select RPC. The struct fd_set seen on EE
136+
* (newlib, ~128 bytes) and IOP (lwIP, MEMP_NUM_NETCONN/8 bytes) compile
137+
* units differs in size, which used to scramble select_pkt's layout
138+
* across the SIF RPC boundary — IOP would only touch the first few
139+
* bytes of EE's wider readset and never see writeset/exceptset at the
140+
* right offsets. Using a fixed-size struct here keeps select_pkt
141+
* byte-identical on both sides regardless of which struct fd_set is
142+
* in scope at the include site. */
143+
typedef struct
144+
{
145+
unsigned char fd_bits[(MEMP_NUM_NETCONN + 7) / 8];
146+
} ps2ip_rpc_fd_set;
147+
148+
/* struct timeval differs across the boundary too — newlib's tv_sec/tv_usec
149+
* are 64-bit on EE while the IOP defines them as 32-bit longs. Carry
150+
* explicit 32-bit fields here so the layout is byte-identical on both
151+
* sides; each end reconstructs its native struct timeval. */
135152
typedef struct
136153
{
137154
union
138155
{
139156
s32 maxfdp1;
140157
s32 result;
141158
};
142-
struct timeval *timeout_p;
143-
struct timeval timeout;
144-
struct fd_set *readset_p;
145-
struct fd_set *writeset_p;
146-
struct fd_set *exceptset_p;
147-
struct fd_set readset;
148-
struct fd_set writeset;
149-
struct fd_set exceptset;
159+
void *timeout_p; /* opaque NULL/non-NULL flag */
160+
s32 timeout_sec;
161+
s32 timeout_usec;
162+
void *readset_p; /* opaque: only NULL/non-NULL is meaningful across RPC */
163+
void *writeset_p;
164+
void *exceptset_p;
165+
ps2ip_rpc_fd_set readset;
166+
ps2ip_rpc_fd_set writeset;
167+
ps2ip_rpc_fd_set exceptset;
150168
} select_pkt;
151169

152170
typedef struct

ee/rpc/tcpips/src/ps2ipc.c

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,38 @@ int ps2ipc_ps2ip_getconfig(char *netif_name, t_ip_info *ip_info)
481481
return 1;
482482
}
483483

484+
/* Marshal between the caller's struct fd_set (newlib, ~128 bytes on EE)
485+
* and the on-the-wire ps2ip_rpc_fd_set (MEMP_NUM_NETCONN/8 bytes, fixed
486+
* size on both sides). Bit-by-bit copy avoids any reliance on
487+
* sizeof(struct fd_set) matching across the RPC boundary. */
488+
static void ps2ipc_pack_fdset(ps2ip_rpc_fd_set *dst, struct fd_set *src, int maxfdp1)
489+
{
490+
int i;
491+
memset(dst, 0, sizeof(*dst));
492+
if (src == NULL) return;
493+
if (maxfdp1 > (int)(sizeof(dst->fd_bits) * 8))
494+
maxfdp1 = (int)(sizeof(dst->fd_bits) * 8);
495+
for (i = 0; i < maxfdp1; i++) {
496+
if (FD_ISSET(i, src)) {
497+
dst->fd_bits[i >> 3] |= (unsigned char)(1U << (i & 7));
498+
}
499+
}
500+
}
501+
502+
static void ps2ipc_unpack_fdset(struct fd_set *dst, const ps2ip_rpc_fd_set *src, int maxfdp1)
503+
{
504+
int i;
505+
if (dst == NULL) return;
506+
FD_ZERO(dst);
507+
if (maxfdp1 > (int)(sizeof(src->fd_bits) * 8))
508+
maxfdp1 = (int)(sizeof(src->fd_bits) * 8);
509+
for (i = 0; i < maxfdp1; i++) {
510+
if (src->fd_bits[i >> 3] & (1U << (i & 7))) {
511+
FD_SET(i, dst);
512+
}
513+
}
514+
}
515+
484516
int ps2ipc_select(int maxfdp1, struct fd_set *readset, struct fd_set *writeset, struct fd_set *exceptset, struct timeval *timeout)
485517
{
486518
int result;
@@ -491,21 +523,19 @@ int ps2ipc_select(int maxfdp1, struct fd_set *readset, struct fd_set *writeset,
491523
WaitSema(lock_sema);
492524

493525
pkt->maxfdp1 = maxfdp1;
494-
pkt->readset_p = readset;
495-
pkt->writeset_p = writeset;
496-
pkt->exceptset_p = exceptset;
526+
pkt->readset_p = (void *)readset;
527+
pkt->writeset_p = (void *)writeset;
528+
pkt->exceptset_p = (void *)exceptset;
497529
pkt->timeout_p = timeout;
498530
if( timeout )
499-
pkt->timeout = *timeout;
500-
501-
if( readset )
502-
pkt->readset = *readset;
503-
504-
if( writeset )
505-
pkt->writeset = *writeset;
531+
{
532+
pkt->timeout_sec = (s32)timeout->tv_sec;
533+
pkt->timeout_usec = (s32)timeout->tv_usec;
534+
}
506535

507-
if( exceptset )
508-
pkt->exceptset = *exceptset;
536+
ps2ipc_pack_fdset(&pkt->readset, readset, maxfdp1);
537+
ps2ipc_pack_fdset(&pkt->writeset, writeset, maxfdp1);
538+
ps2ipc_pack_fdset(&pkt->exceptset, exceptset, maxfdp1);
509539

510540
if (sceSifCallRpc(&_ps2ip, PS2IPS_ID_SELECT, 0, (void*)pkt, sizeof(select_pkt), (void*)pkt, sizeof(select_pkt), NULL, NULL) < 0)
511541
{
@@ -514,16 +544,14 @@ int ps2ipc_select(int maxfdp1, struct fd_set *readset, struct fd_set *writeset,
514544
}
515545

516546
if( timeout )
517-
*timeout = pkt->timeout;
518-
519-
if( readset )
520-
*readset = pkt->readset;
521-
522-
if( writeset )
523-
*writeset = pkt->writeset;
547+
{
548+
timeout->tv_sec = pkt->timeout_sec;
549+
timeout->tv_usec = pkt->timeout_usec;
550+
}
524551

525-
if( exceptset )
526-
*exceptset = pkt->exceptset;
552+
ps2ipc_unpack_fdset(readset, &pkt->readset, maxfdp1);
553+
ps2ipc_unpack_fdset(writeset, &pkt->writeset, maxfdp1);
554+
ps2ipc_unpack_fdset(exceptset, &pkt->exceptset, maxfdp1);
527555

528556
result = pkt->result;
529557

iop/tcpip/tcpips/src/ps2ips.c

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -402,15 +402,34 @@ static void do_setconfig(void *rpcBuffer, int size)
402402
static void do_select( void * rpcBuffer, int size )
403403
{
404404
select_pkt *pkt = (select_pkt*)_rpc_buffer;
405+
struct timeval tv;
406+
int result;
405407

406408
(void)rpcBuffer;
407409
(void)size;
408410

409-
pkt->result = select( pkt->maxfdp1,
410-
pkt->readset_p != NULL ? &pkt->readset : NULL,
411-
pkt->writeset_p != NULL ? &pkt->writeset : NULL,
412-
pkt->exceptset_p != NULL ? &pkt->exceptset : NULL,
413-
pkt->timeout_p != NULL ? &pkt->timeout : NULL );
411+
/* Reconstruct an IOP-native struct timeval from the wire fields. */
412+
if (pkt->timeout_p != NULL)
413+
{
414+
tv.tv_sec = pkt->timeout_sec;
415+
tv.tv_usec = pkt->timeout_usec;
416+
}
417+
418+
/* ps2ip_rpc_fd_set is { unsigned char fd_bits[(MEMP_NUM_NETCONN+7)/8] },
419+
* which is byte-identical to lwIP's struct fd_set. The cast is safe and
420+
* keeps lwip_select free to mutate the bits in place. */
421+
result = select( pkt->maxfdp1,
422+
pkt->readset_p != NULL ? (struct fd_set *)&pkt->readset : NULL,
423+
pkt->writeset_p != NULL ? (struct fd_set *)&pkt->writeset : NULL,
424+
pkt->exceptset_p != NULL ? (struct fd_set *)&pkt->exceptset : NULL,
425+
pkt->timeout_p != NULL ? &tv : NULL );
426+
427+
if (pkt->timeout_p != NULL)
428+
{
429+
pkt->timeout_sec = (s32)tv.tv_sec;
430+
pkt->timeout_usec = (s32)tv.tv_usec;
431+
}
432+
pkt->result = result;
414433
}
415434

416435
static void do_ioctlsocket( void *rpcBuffer, int size )

0 commit comments

Comments
 (0)