Skip to content

Commit 8beead0

Browse files
authored
Merge pull request #838 from fjtrujy/upgrade_lwip_v2
lwIP: upgrade to upstream STABLE-2_2_1_RELEASE
2 parents 57ae7d9 + b509ee3 commit 8beead0

14 files changed

Lines changed: 195 additions & 76 deletions

File tree

download_dependencies.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ fi
1616
## Download LWIP (upstream, unpatched)
1717
LWIP_REPO_URL="https://github.com/lwip-tcpip/lwip.git"
1818
LWIP_REPO_FOLDER="common/external_deps/lwip"
19-
LWIP_BRANCH_NAME="STABLE-2_0_3_RELEASE"
19+
LWIP_BRANCH_NAME="STABLE-2_2_1_RELEASE"
2020
if test ! -d "$LWIP_REPO_FOLDER"; then
2121
git clone --depth 1 -b $LWIP_BRANCH_NAME $LWIP_REPO_URL "$LWIP_REPO_FOLDER"_inprogress || exit 1
2222
mv "$LWIP_REPO_FOLDER"_inprogress "$LWIP_REPO_FOLDER"

ee/network/tcpip/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ ps2api_OBJECTS = \
4444
tcpip.o
4545

4646
ps2api_IPV4 = \
47+
acd.o \
4748
icmp.o \
4849
ip.o \
4950
ip4.o \
@@ -114,6 +115,9 @@ $(EE_OBJS_DIR)api_msg.o: $(LWIP)/src/api/api_msg.c
114115
$(EE_OBJS_DIR)api_netbuf.o: $(LWIP)/src/api/netbuf.c
115116
$(EE_CC) $(EE_CFLAGS) $(EE_INCS) -c $< -o $@
116117

118+
$(EE_OBJS_DIR)acd.o: $(LWIP)/src/core/ipv4/acd.c
119+
$(EE_CC) $(EE_CFLAGS) $(EE_INCS) -c $< -o $@
120+
117121
$(EE_OBJS_DIR)icmp.o: $(LWIP)/src/core/ipv4/icmp.c
118122
$(EE_CC) $(EE_CFLAGS) $(EE_INCS) -c $< -o $@
119123

ee/network/tcpip/src/include/lwipopts.h

Lines changed: 58 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,47 @@
4141
------------------------------------
4242
*/
4343
/**
44-
* MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by the C-library
45-
* instead of lwIP's internal allocator. Default is 0; enabled on EE
46-
* because newlib's malloc is already linked in and the heap pool is
47-
* cheaper than a duplicate lwIP heap.
44+
* MEM_LIBC_MALLOC==1: use libc's malloc/free for lwIP's mem_malloc /
45+
* mem_free (which serve PBUF_RAM allocations and a handful of other
46+
* sites — DHCP options, ARP, DNS, slip/ppp/zepif which we don't build).
47+
* Internally lwIP's pbuf_alloc(PBUF_RAM) computes the payload pointer
48+
* with `LWIP_MEM_ALIGN(p + SIZEOF_STRUCT_PBUF + offset)`, which only
49+
* stays inside the allocated chunk when 'p' is already MEM_ALIGNMENT-
50+
* aligned. That is why MEM_ALIGNMENT must match the underlying
51+
* allocator's alignment — see MEM_ALIGNMENT below.
4852
*/
4953
#define MEM_LIBC_MALLOC 1
5054

51-
/* MEM_ALIGNMENT: should be set to the alignment of the CPU for which
52-
lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2
53-
byte alignment -> define MEM_ALIGNMENT to 2. */
54-
#define MEM_ALIGNMENT 64 //SP193: must be 64, to deal with the EE cache design.
55+
/* MEM_ALIGNMENT: must equal the alignment libc's malloc returns,
56+
because pbuf_alloc(PBUF_RAM) computes
57+
payload = LWIP_MEM_ALIGN(p + SIZEOF_STRUCT_PBUF + offset)
58+
inside an allocation sized assuming p is already MEM_ALIGNMENT-
59+
aligned. If MEM_ALIGNMENT > newlib's alignment the payload pointer
60+
overruns the chunk and corrupts the next-chunk header on the
61+
freelist (TLB misses inside _malloc_r / _free_r).
62+
63+
16 is the contract baked into the toolchain configuration. See
64+
newlib/newlib/configure.host:
65+
66+
mips64r5900*)
67+
machine_dir=r5900
68+
newlib_cflags="${newlib_cflags} -DMALLOC_ALIGNMENT=16"
69+
;;
70+
71+
so for the mips64r5900el-ps2-elf target newlib is built with
72+
-DMALLOC_ALIGNMENT=16, which sets _mallocr.c's MALLOC_ALIGNMENT
73+
directly (overriding the SIZE_SZ-derived default of 8). 16 is also
74+
what samples/malloc_stress observes empirically.
75+
76+
The historical value here was 64 with a comment about "the EE cache
77+
design" (SP193). That was over-cautious: PBUF_POOL pbufs (the only
78+
ones touched by IOP->EE DMA + cache invalidate) come from memp's
79+
static pools and are always 64-byte aligned regardless of
80+
MEM_ALIGNMENT; PBUF_RAM pbufs (TX, ARP, DNS, ...) only see DMA
81+
writeback, where misalignment harmlessly over-flushes extra cache
82+
lines. The IOP-side lwipopts has used MEM_ALIGNMENT=4 forever for
83+
the same reason. */
84+
#define MEM_ALIGNMENT 16
5585

5686
/**
5787
* MEM_SIZE: the size of the heap memory. If the application will send
@@ -103,12 +133,19 @@
103133
#define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN
104134

105135
/**
106-
* LWIP_TCPIP_CORE_LOCKING_INPUT: when LWIP_TCPIP_CORE_LOCKING is enabled,
107-
* this lets tcpip_input() grab the mutex for input packets as well,
108-
* instead of allocating a message and passing it to tcpip_thread.
109-
*
110-
* ATTENTION: this does not work when tcpip_input() is called from
111-
* interrupt context!
136+
* LWIP_TCPIP_CORE_LOCKING==1: matches lwIP 2.2.1's upstream default. With
137+
* LWIP_COMPAT_MUTEX in arch/cc.h the core lock is a binary semaphore taken
138+
* directly on the calling app thread for socket/netconn API calls; lwIP
139+
* releases it before any blocking I/O wait so the tcpip thread + netif
140+
* input continue to make progress. Saves a context switch + sem wait per
141+
* API call versus the message-passing alternative.
142+
*/
143+
#define LWIP_TCPIP_CORE_LOCKING 1
144+
145+
/**
146+
* LWIP_TCPIP_CORE_LOCKING_INPUT==1: tcpip_input() takes the core mutex
147+
* directly instead of allocating a message. Safe here because the netif
148+
* input callback runs in a regular thread, not interrupt context.
112149
*/
113150
#define LWIP_TCPIP_CORE_LOCKING_INPUT 1
114151

@@ -134,18 +171,13 @@
134171
#define LWIP_DHCP 1
135172
#endif
136173

137-
/**
138-
* DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address.
139-
*/
140-
#define DHCP_DOES_ARP_CHECK 0 //Don't do the ARP check because an IP address would be first required.
141-
142-
/**
143-
* LWIP_DHCP_CHECK_LINK_UP==1: dhcp_start() only really starts if the netif has
144-
* NETIF_FLAG_LINK_UP set in its flags. As this is only an optimization and
145-
* netif drivers might not set this flag, the default is off. If enabled,
146-
* netif_set_link_up() must be called to continue dhcp starting.
147-
*/
148-
#define LWIP_DHCP_CHECK_LINK_UP 1
174+
/* LWIP_DHCP_DOES_ACD_CHECK / LWIP_ACD left at upstream defaults (=1 when
175+
* LWIP_DHCP=1) so the RFC 5227 Address Conflict Detection probe runs on
176+
* any DHCP-offered IP. EE applications run on user home networks where
177+
* IP collisions are a real (if uncommon) failure mode; the few KB of
178+
* code and ~1-2 s extra DHCP-bind delay are worth the robustness. The
179+
* IOP lwIP build forces both off because ps2link runs in controlled
180+
* bench environments where the IRX size + tick savings matter more. */
149181

150182
/*
151183
----------------------------------
@@ -208,10 +240,6 @@
208240
---------- Socket options ----------
209241
------------------------------------
210242
*/
211-
/* LWIP_SOCKET_SET_ERRNO==1: Set errno when socket functions cannot complete
212-
* successfully, as required by POSIX. Default is POSIX-compliant.
213-
*/
214-
#define LWIP_SOCKET_SET_ERRNO 0
215243
/**
216244
* LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names.
217245
* Disable this option if you use a POSIX operating system that uses the same

ee/network/tcpip/src/sys_arch.c

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,15 @@ err_t sys_mbox_trypost(sys_mbox_t *mbox, void *sys_msg)
338338
return result;
339339
}
340340

341+
/* lwIP 2.2.x distinguishes ISR-context posts from task-context posts.
342+
The PS2 EE has preemptive scheduling, but our netif input does not run
343+
in interrupt context (it goes through ps2ip / SIF callbacks on the EE
344+
tcpip thread), so the two paths are equivalent here. */
345+
err_t sys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg)
346+
{
347+
return sys_mbox_trypost(mbox, msg);
348+
}
349+
341350
void sys_mbox_post(sys_mbox_t *mbox, void *sys_msg)
342351
{
343352
SendMbx(mbox, alloc_msg(), sys_msg);
@@ -415,6 +424,52 @@ void sys_sem_set_invalid(sys_sem_t *sem){
415424
*sem=SYS_SEM_NULL;
416425
}
417426

427+
/* Semaphore-based critical section for lwIP. Replaces the previous
428+
* DIntr/EIntr approach, which was unsafe: any code path inside a
429+
* SYS_ARCH_PROTECT region that ended up calling newlib's malloc/free
430+
* would try to WaitSema on the heap recursive mutex with interrupts
431+
* disabled, deadlocking the EE. The sema-based variant lets nested
432+
* waits work normally and removes the EE-specific incompatibility
433+
* between lwIP and any other library that uses newlib's locks.
434+
*
435+
* Recursive ownership: lwIP allows SYS_ARCH_PROTECT to nest, so we
436+
* track the owning thread + a recursion counter and only Wait/Signal
437+
* on the outermost transitions.
438+
*/
439+
static int s_protect_sem = -1;
440+
static int s_protect_count = 0;
441+
static int s_protect_owner = -1;
442+
443+
sys_prot_t sys_arch_protect(void)
444+
{
445+
int tid = GetThreadId();
446+
if (s_protect_count > 0 && s_protect_owner == tid)
447+
{
448+
s_protect_count++;
449+
return 0; /* nested re-entry; outer call will release */
450+
}
451+
WaitSema(s_protect_sem);
452+
s_protect_owner = tid;
453+
s_protect_count = 1;
454+
return 1; /* outermost level; matching unprotect will release */
455+
}
456+
457+
void sys_arch_unprotect(sys_prot_t level)
458+
{
459+
if (level == 0)
460+
{
461+
/* nested unprotect; just decrement */
462+
if (s_protect_count > 0)
463+
{
464+
s_protect_count--;
465+
}
466+
return;
467+
}
468+
s_protect_count = 0;
469+
s_protect_owner = -1;
470+
SignalSema(s_protect_sem);
471+
}
472+
418473
void sys_init(void)
419474
{
420475
arch_message *prev;
@@ -428,6 +483,15 @@ void sys_init(void)
428483
sema.init_count = sema.max_count = SYS_MAX_MESSAGES;
429484
MsgCountSema=CreateSema(&sema);
430485

486+
/* Critical-section sema: binary mutex (init=1, max=1). */
487+
sema.attr = 0;
488+
sema.option = (u32)"PS2IP_PROTECT";
489+
sema.init_count = 1;
490+
sema.max_count = 1;
491+
s_protect_sem = CreateSema(&sema);
492+
s_protect_count = 0;
493+
s_protect_owner = -1;
494+
431495
free_head = &msg_pool[0];
432496
prev = &msg_pool[0];
433497

@@ -446,17 +510,6 @@ u32_t sys_now(void)
446510
return(clock()/1000);
447511
}
448512

449-
sys_prot_t sys_arch_protect(void)
450-
{
451-
return DIntr();
452-
}
453-
454-
void sys_arch_unprotect(sys_prot_t level)
455-
{
456-
if(level)
457-
EIntr();
458-
}
459-
460513
void *ps2ip_calloc64(size_t n, size_t size)
461514
{
462515
void *ptr = NULL;

iop/network/smap/src/imports.lst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ I_inet_addr
6666
I_tcpip_input
6767
I_netif_set_link_up
6868
I_netif_set_link_down
69-
I_tcpip_callback_with_block
69+
I_tcpip_callback
7070
ps2ip_IMPORTS_end
7171
#endif
7272

iop/tcpip/tcpip-base/include/lwipopts.h

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,21 @@
88

99
/* ---------- Thread options ---------- */
1010
/**
11-
* DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread.
12-
* The stack size value itself is platform-dependent, but is passed to
13-
* sys_thread_new() when the thread is created.
11+
* DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread
12+
* spawned via sys_thread_new(). In our build that's just the tcpip thread.
13+
*
14+
* With LWIP_TCPIP_CORE_LOCKING=1 the deep socket-API call chains run on
15+
* the calling app thread, not on the tcpip thread; the tcpip thread itself
16+
* only dispatches timer callbacks and the occasional tcpip_callback (e.g.
17+
* link up/down). Worst-case chain on the tcpip thread is roughly
18+
*
19+
* tcpip_thread (56) -> sys_check_timeouts (32) -> lwip_cyclic_timer (32)
20+
* -> tcp_slowtmr (72) or dhcp_fine_tmr -> ~150-200 of inner work
21+
* ~= 350-450 bytes + register-save overhead.
22+
*
23+
* 0x600 (1.5 KB) is the historical 2.0.3 value and matches the call-chain
24+
* profile under LWIP_TCPIP_CORE_LOCKING=1. ~2x margin over the measured
25+
* worst case.
1426
*/
1527
#define DEFAULT_THREAD_STACKSIZE 0x600
1628

@@ -108,12 +120,20 @@
108120
#define PBUF_POOL_SIZE 32 //SP193: should be at least ((TCP_WND/PBUF_POOL_BUFSIZE)+1). But that is too small to handle simultaneous connections.
109121

110122
/**
111-
* LWIP_TCPIP_CORE_LOCKING_INPUT: when LWIP_TCPIP_CORE_LOCKING is enabled,
112-
* this lets tcpip_input() grab the mutex for input packets as well,
113-
* instead of allocating a message and passing it to tcpip_thread.
114-
*
115-
* ATTENTION: this does not work when tcpip_input() is called from
116-
* interrupt context!
123+
* LWIP_TCPIP_CORE_LOCKING==1: matches lwIP 2.2.1's upstream default. Socket
124+
* and netconn API calls take the core mutex on the calling app thread and
125+
* run synchronously, instead of round-tripping through the tcpip thread's
126+
* mailbox. Saves a context switch + sem wait per API call. lwIP releases
127+
* the core lock before any blocking I/O wait (mbox_fetch on connection
128+
* mboxes), so the tcpip thread and SMAP RX can still run to deliver data.
129+
*/
130+
#define LWIP_TCPIP_CORE_LOCKING 1
131+
132+
/**
133+
* LWIP_TCPIP_CORE_LOCKING_INPUT==1: tcpip_input() takes the core mutex
134+
* directly instead of allocating a message. Safe here because the netif
135+
* input callback runs in IntrHandlerThread (smap.c) — a normal thread,
136+
* not interrupt context — so the lock acquire is allowed.
117137
*/
118138
#define LWIP_TCPIP_CORE_LOCKING_INPUT 1
119139

@@ -140,17 +160,14 @@
140160
#endif
141161

142162
/**
143-
* DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address.
144-
*/
145-
#define DHCP_DOES_ARP_CHECK 0 //Don't do the ARP check because an IP address would be first required.
146-
147-
/**
148-
* LWIP_DHCP_CHECK_LINK_UP==1: dhcp_start() only really starts if the netif has
149-
* NETIF_FLAG_LINK_UP set in its flags. As this is only an optimization and
150-
* netif drivers might not set this flag, the default is off. If enabled,
151-
* netif_set_link_up() must be called to continue dhcp starting.
163+
* LWIP_DHCP_DOES_ACD_CHECK==0: skip RFC 5227 Address Conflict Detection on
164+
* the DHCP-offered address (replaces the pre-2.2.0 DHCP_DOES_ARP_CHECK).
165+
* PS2 networking targets a controlled LAN; the saved code+timer/RAM beats
166+
* guarding against a vanishingly unlikely IP collision. Combined with
167+
* LWIP_AUTOIP=0 (default) this lets LWIP_ACD default to 0 too.
152168
*/
153-
#define LWIP_DHCP_CHECK_LINK_UP 1
169+
#define LWIP_DHCP_DOES_ACD_CHECK 0
170+
#define LWIP_ACD 0
154171

155172
/*
156173
----------------------------------
@@ -213,10 +230,6 @@
213230
---------- Socket options ----------
214231
------------------------------------
215232
*/
216-
/* LWIP_SOCKET_SET_ERRNO==1: Set errno when socket functions cannot complete
217-
* successfully, as required by POSIX. Default is POSIX-compliant.
218-
*/
219-
#define LWIP_SOCKET_SET_ERRNO 0
220233
/**
221234
* LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names.
222235
* Disable this option if you use a POSIX operating system that uses the same

iop/tcpip/tcpip-base/sys_arch.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,13 @@ err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg){
182182
return result;
183183
}
184184

185+
/* lwIP 2.2.x distinguishes ISR-context posts from task-context posts. The
186+
IOP has cooperative scheduling and no preemptive ISRs that interact with
187+
the lwIP message queue, so the two are equivalent here. */
188+
err_t sys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg){
189+
return sys_mbox_trypost(mbox, msg);
190+
}
191+
185192
void sys_mbox_post(sys_mbox_t *mbox, void *msg)
186193
{
187194
arch_message *MsgPkt;

iop/tcpip/tcpip-netman/src/exports.tab

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ DECLARE_EXPORT_TABLE(ps2ip, 2, 6)
6565
#endif
6666
DECLARE_EXPORT(netif_set_link_up)
6767
DECLARE_EXPORT(netif_set_link_down) //55
68-
DECLARE_EXPORT(tcpip_callback_with_block)
68+
DECLARE_EXPORT(tcpip_callback)
6969
DECLARE_EXPORT(pbuf_coalesce)
7070
END_EXPORT_TABLE
7171

iop/tcpip/tcpip-netman/src/imports.lst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,16 @@ I_memset
5454
I_strcpy
5555
I_strncpy
5656
I_memcpy
57+
I_memmove
5758
I_strlen
5859
I_strncmp
5960
I_strtok
6061
I_strtoul
6162
I_memcmp
6263
I_strtol
6364
I_strcmp
65+
I_tolower
66+
I_look_ctype_table
6467
sysclib_IMPORTS_end
6568

6669
sysmem_IMPORTS_start

iop/tcpip/tcpip-netman/src/ps2ip.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@
3535

3636
#include "ps2ip_internal.h"
3737

38+
/* lwIP 2.2.1's sockets.c writes errno via set_errno(); the IOP IRX has no
39+
libc-provided errno storage, so we define it here. The ".data" section
40+
name (with leading dot) is critical: a bare "data" attribute creates a
41+
separate section that the IRX loader never allocates into IOP RAM, so
42+
every set_errno() write would corrupt random memory. */
43+
int errno __attribute__((section(".data")));
44+
3845
typedef struct pbuf PBuf;
3946
typedef struct netif NetIF;
4047
typedef struct ip4_addr IPAddr;

0 commit comments

Comments
 (0)