Index: netd_gatesrv.cc
===================================================================
--- netd_gatesrv.cc	(revision 7456)
+++ netd_gatesrv.cc	(working copy)
@@ -10,6 +10,7 @@
 #include <inc/setjmp.h>
 #include <inc/atomic.h>
 #include <inc/utrap.h>
+#include <inc/stack.h>
 #include <netd/netdipc.h>
 
 #include <stdlib.h>
@@ -24,6 +25,16 @@
 #include <inc/scopeguard.hh>
 #include <netd/netdsrv.hh>
 
+struct fast_args {
+    struct cobj_ref stackobj;
+    void *stackbase;
+    struct cobj_ref ipc_seg;
+    struct netd_ipc_segment *ipc;
+    uint64_t bytes;
+    struct cobj_ref temp_as;
+    netd_handler h;
+};
+
 static uint64_t netd_server_enabled;
 static struct cobj_ref declassify_gate;
 static struct cobj_ref netd_asref;
@@ -67,65 +78,31 @@
     rg->ret(0, 0, 0);
 }
 
-static void
-netd_ipc_setup(uint64_t taint_ct, struct cobj_ref ipc_seg, uint64_t flags, 
-	       void **va, uint64_t *bytes, struct cobj_ref *temp_as)
+void __attribute__((noreturn))
+netd_fast_cleanup(struct fast_args *args)
 {
-    uint64_t netd_ct = start_env->proc_container;
-
-    error_check(sys_self_addref(netd_ct));
-    scope_guard<int, cobj_ref> unref(sys_obj_unref, COBJ(netd_ct, thread_id()));
-    
-    // Create private container backed by user resources + AS clone
-    {
-	label private_label;
-	thread_cur_label(&private_label);
-	private_label.transform(label::star_to, private_label.get_default());
-	private_label.set(start_env->process_grant, 0);
-	private_label.set(start_env->process_taint, 3);
-	
-	int64_t private_ct;
-	error_check(private_ct =
-		    sys_container_alloc(taint_ct, private_label.to_ulabel(),
-					"netd_fast private", 0, CT_QUOTA_INF));
-	
-	int64_t asid;
-	error_check(asid = sys_as_copy(netd_asref, private_ct,
-				       0, "netd_ipc temp AS"));
-	*temp_as = COBJ(private_ct, asid);
-    }
-    
-    error_check(sys_self_set_as(*temp_as));
-    segment_as_switched();
-    error_check(segment_map(ipc_seg, 0, flags, va, bytes, 0));
+    struct cobj_ref o = args->stackobj;
+    segment_unmap(args->stackbase);
+    sys_obj_unref(o);
+    thread_halt();
 }
 
 static void __attribute__((noreturn))
-netd_fast_gate_entry(uint64_t a, struct gate_call_data *gcd, gatesrv_return *rg)
+netd_fast_server(struct fast_args *args)
 {
-    netd_handler h = (netd_handler) (uintptr_t) a;
+    struct netd_ipc_segment *ipc = args->ipc;
     uint64_t netd_ct = start_env->proc_container;
-    struct cobj_ref temp_as;
-    struct netd_ipc_segment *ipc = 0;
-    uint64_t map_bytes = 0;
 
-    error_check(sys_segment_resize(COBJ(0, kobject_id_thread_sg), 2 * PGSIZE));
-
-    while (!netd_server_enabled)
-	sys_sync_wait(&netd_server_enabled, 0, UINT64(~0));
-
-    netd_ipc_setup(gcd->taint_container, gcd->param_obj, 
-		   SEGMAP_READ | SEGMAP_WRITE,
-		   (void **) &ipc, &map_bytes, &temp_as);
-
     struct jos_jmp_buf pgfault;
-    if (jos_setjmp(&pgfault) != 0)
-	thread_halt();
+    if (jos_setjmp(&pgfault) != 0) {
+	stack_switch((uint64_t)(uintptr_t)args, 0, 0, 0,
+		     (char *)tls_stack_top - 8, (void *) &netd_fast_cleanup);
+    }
     tls_data->tls_pgfault = &pgfault;
 
-    if (map_bytes != sizeof(*ipc))
+    if (args->bytes != sizeof(*ipc))
 	throw basic_exception("wrong size IPC segment: %"PRIu64" should be %"PRIu64"\n",
-			      map_bytes, (uint64_t) sizeof(*ipc));
+			      args->bytes, (uint64_t) sizeof(*ipc));
 
     for (;;) {
 	while (ipc->sync == NETD_IPC_SYNC_REPLY)
@@ -140,10 +117,10 @@
 	// Map shared memory segment & execute operation
 	{
 	    struct netd_ipc_segment *ipc_shared = 0;
-	    error_check(segment_map(gcd->param_obj, 0,
+	    error_check(segment_map(args->ipc_seg, 0,
 				    SEGMAP_READ | SEGMAP_WRITE
 						| SEGMAP_VECTOR_PF,
-				    (void **) &ipc_shared, &map_bytes, 0));
+				    (void **) &ipc_shared, &args->bytes, 0));
 	    scope_guard<int, void *> unmap(segment_unmap, ipc_shared);
 
 	    struct netd_ipc_segment *ipc_copy;
@@ -162,7 +139,7 @@
 	    while (ipc_shared->sync == NETD_IPC_SYNC_REQUEST) {
 		memcpy(&ipc_copy->args, &ipc_shared->args,
 		       ipc_shared->args.size);
-		h(&ipc_copy->args);
+		args->h(&ipc_copy->args);
 		memcpy(&ipc_shared->args, &ipc_copy->args,
 		       ipc_copy->args.size);
 
@@ -180,10 +157,82 @@
 	}
 
 	unref.force();
-	error_check(sys_self_set_as(temp_as));
+	error_check(sys_self_set_as(args->temp_as));
     }
+    
+    stack_switch((uint64_t)(uintptr_t)args, 0, 0, 0,
+		 (char *)tls_stack_top - 8, (void *) &netd_fast_cleanup);
+}
 
-    thread_halt();
+static void __attribute__((noreturn))
+netd_fast_gate_entry(uint64_t a, struct gate_call_data *gcd, gatesrv_return *rg)
+{
+    netd_handler h = (netd_handler) (uintptr_t) a;
+    struct netd_ipc_segment *ipc = 0;
+
+    error_check(sys_segment_resize(COBJ(0, kobject_id_thread_sg), 2 * PGSIZE));
+
+    while (!netd_server_enabled)
+	sys_sync_wait(&netd_server_enabled, 0, UINT64(~0));
+
+    uint64_t netd_ct = start_env->proc_container;
+
+    error_check(sys_self_addref(netd_ct));
+    scope_guard<int, cobj_ref> unref(sys_obj_unref, COBJ(netd_ct, thread_id()));
+
+    struct cobj_ref stackobj;
+    void *stackbase = 0;
+    char *stacktop;
+    
+    struct cobj_ref temp_as;
+
+    // Create private container backed by user resources + AS clone
+    {
+	label private_label;
+	thread_cur_label(&private_label);
+	private_label.transform(label::star_to, private_label.get_default());
+	private_label.set(start_env->process_grant, 0);
+	private_label.set(start_env->process_taint, 3);
+	
+	int64_t private_ct;
+	error_check(private_ct =
+		    sys_container_alloc(gcd->taint_container, private_label.to_ulabel(),
+					"netd_fast private", 0, CT_QUOTA_INF));
+
+	error_check(segment_alloc(netd_ct, PGSIZE, &stackobj,
+				  0, 0, "netd_fast stack"));
+	scope_guard<int, cobj_ref> s(sys_obj_unref, stackobj);
+	
+	uint64_t stackbytes = thread_stack_pages * PGSIZE;
+	error_check(segment_map(stackobj, 0, SEGMAP_READ | SEGMAP_WRITE |
+				SEGMAP_STACK | SEGMAP_REVERSE_PAGES,
+				&stackbase, &stackbytes, 0));
+	stacktop = ((char *) stackbase) + stackbytes;
+	s.dismiss();
+		
+	int64_t asid;
+	error_check(asid = sys_as_copy(netd_asref, private_ct,
+				       0, "netd_ipc temp AS"));
+	temp_as = COBJ(private_ct, asid);
+    }
+
+    struct fast_args *args;
+    stacktop -= sizeof(*args);
+    args = (struct fast_args *)stacktop;
+
+    error_check(sys_self_set_as(temp_as));
+    segment_as_switched();
+    error_check(segment_map(gcd->param_obj, 0, SEGMAP_READ | SEGMAP_WRITE, (void **)&ipc, &args->bytes, 0));
+
+    args->stackobj = stackobj;
+    args->stackbase = stackbase;
+    args->ipc = ipc;
+    args->ipc_seg = gcd->param_obj;
+    args->temp_as = temp_as;
+    args->h = h;
+    
+    stack_switch((uint64_t)(uintptr_t)args, 0, 0, 0,
+		 stacktop, (void *) &netd_fast_server);
 }
 
 static void
Index: netd_lwipinit.c
===================================================================
--- netd_lwipinit.c	(revision 7456)
+++ netd_lwipinit.c	(working copy)
@@ -43,18 +43,6 @@
 lwip_init(struct netif *nif, void *if_state,
 	  uint32_t init_addr, uint32_t init_mask, uint32_t init_gw)
 {
-    lwipext_init(1);
-    // lwIP initialization sequence, as suggested by lwip/doc/rawapi.txt
-    stats_init();
-    sys_init();
-    mem_init();
-    memp_init();
-    pbuf_init();
-    etharp_init();
-    ip_init();
-    udp_init();
-    tcp_init();
-
     struct ip_addr ipaddr, netmask, gateway;
     ipaddr.addr  = init_addr;
     netmask.addr = init_mask;
@@ -118,8 +106,9 @@
 static void
 tcpip_init_done(void *arg)
 {
-    sys_sem_t *sem = (sys_sem_t *) arg;
-    sys_sem_signal(*sem);
+    uint64_t *done = arg;
+    *done = 1;
+    sys_sync_wakeup(done);
 }
 
 static const char *
@@ -150,6 +139,14 @@
     if (r < 0)
 	panic("cannot alloc netif: %s\n", e2s(r));
 	
+    lwipext_init(1);
+
+    uint64_t done = 0;
+    tcpip_init(&tcpip_init_done, &done);
+    lwip_core_unlock();
+    sys_sync_wait(&done, 0, UINT64(~0));
+    lwip_core_lock();
+
     lwip_init(nif, if_state, ipaddr, netmask, gw);
 
     if (ipaddr == 0)
@@ -174,11 +171,6 @@
 	start_timer(&t_dhcpc, &dhcp_coarse_tmr,	"dhcp c timer",	DHCP_COARSE_TIMER_SECS * 1000);
     }
 
-    sys_sem_t tcpip_init_sem = sys_sem_new(0);
-    tcpip_init(&tcpip_init_done, &tcpip_init_sem);
-    sys_sem_wait(tcpip_init_sem);
-    sys_sem_free(tcpip_init_sem);
-
     cb(cbarg);
 
     int dhcp_state = 0;
