summaryrefslogtreecommitdiffstats
path: root/src/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/makefile2
-rw-r--r--src/kernel/msghandler.C141
-rw-r--r--src/kernel/syscall.C58
-rw-r--r--src/kernel/vmmmgr.C5
4 files changed, 185 insertions, 21 deletions
diff --git a/src/kernel/makefile b/src/kernel/makefile
index c3af165c9..5ccbf8da9 100644
--- a/src/kernel/makefile
+++ b/src/kernel/makefile
@@ -3,7 +3,7 @@ ROOTPATH = ../..
OBJS = start.o kernel.o console.o pagemgr.o heapmgr.o taskmgr.o cpumgr.o
OBJS += syscall.o scheduler.o spinlock.o exception.o vmmmgr.o timemgr.o
OBJS += futexmgr.o ptmgr.o segmentmgr.o devicesegment.o basesegment.o
-OBJS += block.o cpuid.o misc.o
+OBJS += block.o cpuid.o misc.o msghandler.o
include ${ROOTPATH}/config.mk
diff --git a/src/kernel/msghandler.C b/src/kernel/msghandler.C
new file mode 100644
index 000000000..f5f43fa1e
--- /dev/null
+++ b/src/kernel/msghandler.C
@@ -0,0 +1,141 @@
+#include <assert.h>
+#include <errno.h>
+#include <kernel/msghandler.H>
+#include <kernel/task.H>
+#include <kernel/cpu.H>
+#include <kernel/scheduler.H>
+#include <kernel/taskmgr.H>
+#include <kernel/console.H>
+
+namespace Systemcalls { void TaskEnd(task_t*); };
+
+void MessageHandler::sendMessage(msg_sys_types_t i_type, void* i_key,
+ void* i_data, task_t* i_task)
+{
+ // Save pending info for when we get the response.
+ MessageHandler_Pending* mp = new MessageHandler_Pending;
+ mp->key = i_key;
+ mp->task = i_task;
+
+ // Send userspace message if one hasn't been sent for this key.
+ if (!iv_pending.find(i_key))
+ {
+ // Create message.
+ msg_t* m = new msg_t;
+ m->type = i_type;
+ m->data[0] = reinterpret_cast<uint64_t>(i_key);
+ m->data[1] = reinterpret_cast<uint64_t>(i_data);
+ m->__reserved__async = 1;
+
+ // Create pending response object.
+ MessagePending* mp = new MessagePending();
+ mp->key = m;
+ mp->task = reinterpret_cast<task_t*>(this);
+
+ // Send to userspace...
+ iv_msgq->lock.lock();
+ task_t* waiter = iv_msgq->waiting.remove();
+ if (NULL == waiter) // No waiting task, queue for msg_wait call.
+ {
+ iv_msgq->messages.insert(mp);
+ }
+ else // Waiting task, set msg as return and release.
+ {
+ TASK_SETRTN(waiter, (uint64_t) m);
+ iv_msgq->responses.insert(mp);
+ waiter->cpu = i_task->cpu;
+ TaskManager::setCurrentTask(waiter);
+ }
+ iv_msgq->lock.unlock();
+ }
+
+ // Defer task while waiting for message response.
+ if ((NULL != i_task) && (TaskManager::getCurrentTask() == i_task))
+ {
+ i_task->cpu->scheduler->setNextRunnable();
+ }
+
+ // Insert pending info into our queue until response is recv'd.
+ iv_pending.insert(mp);
+}
+
+int MessageHandler::recvMessage(msg_t* i_msg)
+{
+ // Verify userspace didn't give a non-kernel message type.
+ if (i_msg->type < MSG_FIRST_SYS_TYPE)
+ {
+ return -EINVAL;
+ }
+
+ // Lock subsystem spinlock.
+ if (iv_lock) iv_lock->lock();
+
+ // Get <key, rc> from response.
+ MessageHandler_Pending::key_type key =
+ reinterpret_cast<MessageHandler_Pending::key_type>(i_msg->data[0]);
+ int msg_rc = static_cast<int>(i_msg->data[1]);
+
+ // Handle all pending responses.
+ bool restored_task = false;
+ MessageHandler_Pending* mp = NULL;
+ while (NULL != (mp = iv_pending.find(key)))
+ {
+ // Call 'handle response'.
+ HandleResult rc = this->handleResponse(
+ static_cast<msg_sys_types_t>(i_msg->type),
+ key, mp->task, msg_rc);
+
+ // Remove pending information from outstanding queue.
+ iv_pending.erase(mp);
+ delete mp;
+
+ // If there is no associated task then there is nothing to do, find
+ // next pending response.
+ if (!mp->task) continue;
+
+ // Handle action requested from 'handle response'.
+ if ((SUCCESS == rc) || (!msg_rc && UNHANDLED_RC == rc))
+ {
+ // Successful response, resume task.
+
+ if (!restored_task) // Immediately execute first deferred task.
+ {
+ restored_task = true;
+ TaskManager::setCurrentTask(mp->task);
+ }
+ else // Add other deferred tasks to scheduler ready queue.
+ {
+ mp->task->cpu->scheduler->addTask(mp->task);
+ }
+ }
+ else if (UNHANDLED_RC == rc)
+ {
+ // Unsuccessful, unhandled response. Kill task.
+ printk("Unhandled msg rc %d for key %p on task %d @ %p\n",
+ msg_rc, key, mp->task->tid, mp->task->context.nip);
+ Systemcalls::TaskEnd(mp->task);
+ }
+ else if (CONTINUE_DEFER == rc)
+ {
+ // Requested to continue deferring task. Do nothing.
+ }
+ else
+ {
+ // Logic bug (new HandleResult?). Shouldn't be here.
+ kassert(false);
+ }
+ }
+
+ // Finished handling the response, unlock subsystem.
+ if (iv_lock) iv_lock->unlock();
+
+ return 0;
+}
+
+MessageHandler::HandleResult MessageHandler::handleResponse(
+ msg_sys_types_t i_type, void* i_key, task_t* i_task, int i_rc)
+{
+ // Indicate nothing specific has been done for this response. Request
+ // default behavior of resume/kill task based on rc.
+ return UNHANDLED_RC;
+}
diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C
index 51009195d..a71217bec 100644
--- a/src/kernel/syscall.C
+++ b/src/kernel/syscall.C
@@ -1,4 +1,5 @@
#include <assert.h>
+#include <errno.h>
#include <kernel/cpu.H>
#include <kernel/cpumgr.H>
#include <kernel/scheduler.H>
@@ -12,6 +13,7 @@
#include <kernel/futexmgr.H>
#include <kernel/cpuid.H>
#include <kernel/misc.H>
+#include <kernel/msghandler.H>
extern "C"
void kernel_execute_decrementer()
@@ -110,18 +112,6 @@ void kernel_execute_system_call()
}
}
-#define TASK_GETARGN(t, n) (t->context.gprs[n+4])
-#define TASK_GETARG0(t) (TASK_GETARGN(t,0))
-#define TASK_GETARG1(t) (TASK_GETARGN(t,1))
-#define TASK_GETARG2(t) (TASK_GETARGN(t,2))
-#define TASK_GETARG3(t) (TASK_GETARGN(t,3))
-#define TASK_GETARG4(t) (TASK_GETARGN(t,4))
-#define TASK_GETARG5(t) (TASK_GETARGN(t,5))
-#define TASK_GETARG6(t) (TASK_GETARGN(t,6))
-#define TASK_GETARG7(t) (TASK_GETARGN(t,7))
-
-#define TASK_SETRTN(t, n) (t->context.gprs[3] = (n))
-
namespace Systemcalls
{
void TaskYield(task_t* t)
@@ -186,6 +176,12 @@ namespace Systemcalls
msg_t* m = (msg_t*) TASK_GETARG1(t);
m->__reserved__async = 0; // set to async msg.
+ if (m->type >= MSG_FIRST_SYS_TYPE)
+ {
+ TASK_SETRTN(t, -EINVAL);
+ return;
+ }
+
mq->lock.lock();
// Get waiting (server) task.
@@ -213,11 +209,19 @@ namespace Systemcalls
msg_t* m = (msg_t*) TASK_GETARG1(t);
m->__reserved__async = 1; // set to sync msg.
- mq->lock.lock();
+ if (m->type >= MSG_FIRST_SYS_TYPE)
+ {
+ TASK_SETRTN(t, -EINVAL);
+ return;
+ }
+
+ // Create pending response object.
MessagePending* mp = new MessagePending();
mp->key = m;
mp->task = t;
+ mq->lock.lock();
+
// Get waiting (server) task.
task_t* waiter = mq->waiting.remove();
if (NULL == waiter) // None found, add to 'messages' queue.
@@ -249,20 +253,34 @@ namespace Systemcalls
task_t* waiter = mp->task;
mq->responses.erase(mp);
+ mq->lock.unlock();
delete mp;
- waiter->cpu = t->cpu;
- TaskManager::setCurrentTask(waiter);
- TASK_SETRTN(waiter,0);
-
- TASK_SETRTN(t,0);
- t->cpu->scheduler->addTask(t);
+ if (m->type >= MSG_FIRST_SYS_TYPE)
+ {
+ TASK_SETRTN(t,
+ ((MessageHandler*)waiter)->recvMessage(m));
+
+ if (TaskManager::getCurrentTask() != t)
+ {
+ t->cpu->scheduler->addTask(t);
+ }
+ }
+ else
+ {
+ waiter->cpu = t->cpu;
+ TaskManager::setCurrentTask(waiter);
+ TASK_SETRTN(waiter,0);
+
+ TASK_SETRTN(t,0);
+ t->cpu->scheduler->addTask(t);
+ }
}
else
{
TASK_SETRTN(t, -1);
+ mq->lock.unlock();
}
- mq->lock.unlock();
}
void MsgWait(task_t* t)
diff --git a/src/kernel/vmmmgr.C b/src/kernel/vmmmgr.C
index 46fca9fef..74c3178d0 100644
--- a/src/kernel/vmmmgr.C
+++ b/src/kernel/vmmmgr.C
@@ -111,3 +111,8 @@ int VmmManager::mmAllocBlock(MessageQueue* i_mq,void* i_va,uint64_t i_size)
return BaseSegment::mmAllocBlock(i_mq,i_va,i_size);
}
+Spinlock* VmmManager::getLock()
+{
+ return &Singleton<VmmManager>::instance().lock;
+}
+
OpenPOWER on IntegriCloud