From 06d143d51f1a4adf1365c536ed2b5287e75325e8 Mon Sep 17 00:00:00 2001
From: Norman Feske <norman.feske@genode-labs.com>
Date: Wed, 13 May 2015 11:22:14 +0200
Subject: [PATCH] sel4: receive-sel handling for early IPC

---
 repos/base-sel4/src/base/ipc/ipc.cc | 36 +++++++++++++++++++++++------
 1 file changed, 29 insertions(+), 7 deletions(-)

diff --git a/repos/base-sel4/src/base/ipc/ipc.cc b/repos/base-sel4/src/base/ipc/ipc.cc
index 3390c3bd3a..b9e6212f69 100644
--- a/repos/base-sel4/src/base/ipc/ipc.cc
+++ b/repos/base-sel4/src/base/ipc/ipc.cc
@@ -38,6 +38,26 @@ enum {
 };
 
 
+/**
+ * Return reference to receive selector of the calling thread
+ */
+static unsigned &rcv_sel()
+{
+	/*
+	 * When the function is called at the very early initialization phase,
+	 * we cannot access Thread_base::myself()->tid() because the Thread_base
+	 * object of the main thread does not exist yet. During this phase, we
+	 * return a reference to the 'main_rcv_sel' variable.
+	 */
+	if (Thread_base::myself()) {
+		return Thread_base::myself()->tid().rcv_sel;
+	}
+
+	static unsigned main_rcv_sel = Capability_space::alloc_rcv_sel();
+	return main_rcv_sel;
+}
+
+
 /**
  * Convert Genode::Msgbuf_base content into seL4 message
  *
@@ -77,10 +97,9 @@ static seL4_MessageInfo_t new_seL4_message(Msgbuf_base &msg,
 	/*
 	 * Allocate and define receive selector
 	 */
-	Native_thread &thread = Thread_base::myself()->tid();
 
-	if (!thread.rcv_sel)
-		thread.rcv_sel = Capability_space::alloc_rcv_sel();
+	if (!rcv_sel())
+		rcv_sel() = Capability_space::alloc_rcv_sel();
 
 	/*
 	 * Supply data payload
@@ -174,7 +193,7 @@ static void decode_seL4_message(umword_t badge,
 
 			ASSERT(delegated);
 
-			Native_thread &thread = Thread_base::myself()->tid();
+			ASSERT(delegated);
 
 			Native_capability arg_cap = Capability_space::lookup(rpc_obj_key);
 
@@ -189,14 +208,14 @@ static void decode_seL4_message(umword_t badge,
 				 *      Unfortunaltely, seL4 lacks such a comparison operation.
 				 */
 
-				Capability_space::reset_sel(thread.rcv_sel);
+				Capability_space::reset_sel(rcv_sel());
 
 				dst_msg.append_cap(arg_cap);
 
 			} else {
 
 				Capability_space::Ipc_cap_data const
-					ipc_cap_data(rpc_obj_key, thread.rcv_sel);
+					ipc_cap_data(rpc_obj_key, rcv_sel());
 
 				dst_msg.append_cap(Capability_space::import(ipc_cap_data));
 
@@ -204,7 +223,7 @@ static void decode_seL4_message(umword_t badge,
 				 * Since we keep using the received selector, we need to
 				 * allocate a fresh one for the next incoming delegation.
 				 */
-				thread.rcv_sel = Capability_space::alloc_rcv_sel();
+				rcv_sel() = Capability_space::alloc_rcv_sel();
 			}
 		}
 		curr_sel4_cap_idx++;
@@ -295,6 +314,9 @@ void Ipc_client::_call()
 		kernel_debugger_panic("IPC destination is invalid");
 	}
 
+	if (!rcv_sel())
+		rcv_sel() = Capability_space::alloc_rcv_sel();
+
 	seL4_MessageInfo_t const request_msg_info =
 		new_seL4_message(*_snd_msg, _write_offset);