Kernel messages infrastructure
authorBarret Rhoden <brho@cs.berkeley.edu>
Sat, 20 Mar 2010 02:42:22 +0000 (19:42 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:40 +0000 (17:35 -0700)
Expands the old active messaging mechanisms to support different types
of messages: Immediate and Routine.  This will be the main way of moving
work around (either to another core or delaying with an alarm).  All
usages of existing active messages have been switched to kernel messages
in the immediate mode (which is what they were doing before).  Sparc
does not support routine calls yet, but will shortly.  Read the
Documentation for more details.

This hasn't been tested fully yet - the test cases won't do much, since
the kernel doesn't check for routine messages yet, and the tests occur
during an smp_idle() loop.

20 files changed:
Documentation/kernel_messages.txt [new file with mode: 0644]
Documentation/process-internals.txt
kern/arch/i686/apic.h
kern/arch/i686/smp_boot.c
kern/arch/i686/trap.c
kern/arch/i686/trap.h
kern/arch/i686/trapentry.S
kern/arch/sparc/cpuinfo.c
kern/arch/sparc/smp.c
kern/arch/sparc/trap.c
kern/arch/sparc/trap.h
kern/include/process.h
kern/include/ros/notification.h
kern/include/smp.h
kern/include/testing.h
kern/include/trap.h
kern/src/frontend.c
kern/src/init.c
kern/src/process.c
kern/src/testing.c

diff --git a/Documentation/kernel_messages.txt b/Documentation/kernel_messages.txt
new file mode 100644 (file)
index 0000000..7ab3905
--- /dev/null
@@ -0,0 +1,120 @@
+kernel_messages.txt
+Barret Rhoden
+2010-03-19
+
+This document explains the basic ideas behind our "kernel messages" and some of
+the arcane bits behind the implementation.  These were formerly called active
+messages, since they were an implementation of the low-level hardware messaging.
+
+Overview:
+--------------------------------
+Our kernel messages are just work that is shipped remotely, delayed, or both.
+They currently consist of a PC and a few arguments.  Initially, they were meant
+to be a way to immediately execute code on another core (once interrupts are
+enabled), in the order in which the messages were sent.  This is insufficient
+(and wasn't what we wanted for the task, incidentally).  We simply want to do
+work on another core, but not necessarily instantly.  And not necessarily on
+another core.
+
+Currently, there are two types, distinguished by which list they are sent to per
+core: immediate and routine.  Urgent messages will get executed as soon as
+possible (once interrupts are enabled).  Routine messages will be executed at
+convenient points in the kernel.  This includes when the kernel is about to pop
+back to userspace, or smp_idle()ing.  Routine messages are necessary when their
+function does not return, such as a __startcore, __death, or anything else that
+can ruin whatever the kernel was doing.  They should also be used if the work is
+not worth fully interrupting the kernel.  (An IPI will still be sent, but the
+work will be delayed)
+
+Kernel messages of a given type will be executed in order.  If immediate
+messages show up while processing a routine message, the immediate message will
+get processed next, at the latest.  Even if the routine function doesn't return,
+once interrupts are reenabled (like when popping to userspace), the
+__kernel_message() handler will fire again.
+
+History:
+--------------------------------
+A bit of history: we used to use "immediate" messages (when all messages were
+immediate) for __death calls.  The idea was that we didn't care what the core
+was doing, since we didn't need to save state or anything.  I could see that
+there were going to be issues with preemption, since we would want to do some
+saving of what the core was doing (and what the kernel was doing on its behalf),
+so we prepared to deal with that.  However, even __death could break certain
+codes that were holding a reference (and hence a refcnt) for a process, which
+would prevent the process from ever being cleaned up.  It was a specific case of
+a job that the kernel needed to finish before executing the message.
+
+An example of an immediate message would be a TLB_shootdown.  Check current,
+flush if applicable, and return.  It doesn't harm the kernel at all.  Another
+example would be certain debug routines.
+
+Kernel messages are currently an arch-dependent thing, but this ought to change
+when sparc has IPI functions similar to x86.
+
+Other Uses:
+--------------------------------
+Kernel messages will also be the basis for the alarm system.  All it is is
+expressing work that needs to be done.  That being said, the k_msg struct will
+probably receive a timestamp field, among other things.  Routine messages also
+will replace the old workqueue, which hasn't really been used in 10 months or
+so.
+
+To Return or Not:
+--------------------------------
+Routine k_msgs do not have to return.  Urgent messages must.  The distinction is
+in how they are sent (send_kernel_message() will take a flag), so be careful.
+Technically, an immediate message could not return, but only if the kernel code
+that was interrupted was not holding any locks, mucking with any invariants, or
+otherwise doing work that needed to be done.  Those cases seem rather rare.
+
+Trickiness:
+--------------------------------
+If a function does not return, then the code might not check the list again, or
+send the EOI.  This is one reason why we send the EOI first, and insist that the
+__kernel_message() handler execute with interrupts disabled.  The routine
+messages do not need to have their interrupts disabled (if they are executed
+somewhere else).  If another IPI comes in, immediate messages will run, but
+other routine messages won't (they will get executed when the list is checked
+again).  However, enabling interrupts in the __kernel_message() handler can be
+problematic, depending on when the EOI is sent (nesting on the same code).
+
+The other reason we send_eoi() first is that we can only send it once per
+handler (not per message).  Otherwise, it can start acknowleding other interrupt
+vectors, which is bad.  We might move it in the while loop and protect it with a
+static check, but it doesn't seem worth it.  We still can't turn on interrupts,
+since the self_ipi could would fire and return while processing a routine
+function, negating the intent of the self_ipi.
+
+Since IPIs get "squashed" (my word, meaning if a core receives more than two at
+a time, future IPIs for a vector are ignored), and since functions might not
+return, there is the possibility of losing a message.  There can be more
+messages than IPIs (imagine three k_msgs, each that doesn't return).  To protect
+against this, if there is not an IPI pending (you can check on x86), and if
+there are messages in the routine list, then the code self_ipi's the current
+core.
+
+We don't need to check the immediate list, since we just checked it higher in
+the code (o/w, we wouldn't be executing routine messages).  If an immediate
+showed up since we executed the lapic_send_eoi(), an IPI will be on the way
+(messages are enqueued before sending the IPI).
+
+When we check the routine list, we don't need to lock.  All that macro does is
+check to see if head->item == 0 (and the list head won't get changed).  It's
+basically just a read, which gains no protection from a lock.
+
+Other Notes:
+--------------------------------
+Unproven hunch, but the main performance bottleneck with multiple senders and
+receivers of k_msgs will be the slab allocator.  We use the slab so we can
+dynamically create the k_msgs (can pass them around easily, delay with them
+easily (alarms), and most importantly we can't deadlock by running out of room
+in a static buffer).
+
+Architecture Dependence:
+--------------------------------
+Some details will differ, based on architectural support.  For instance,
+immediate messages can be implemented with true active messages.  Other systems
+with maskable IPI vectors can use a different IPI for routine messages, and that
+interrupt can get masked whenever we enter the kernel (note, that means making
+every trap gate an interrupt gate), and we unmask that interrupt when we want to
+process routine messages.
index ca00168..2175032 100644 (file)
@@ -142,7 +142,7 @@ abandon_core()).
 proc_run(): makes sure enough refcnts are in place for all places that will
 install current.  This also makes it easier on the system (one big incref(n),
 instead of n increfs of (1) from multiple cores).  In the off chance current was
-already set for a core receiving the active message, __startcore will decref.
+already set for a core receiving the kernel message, __startcore will decref.
 Also note that while proc_run() consumes your reference, it's not actually
 decreffing, so there's no danger within proc_run() of the process dying /
 __proc_free()ing.
@@ -283,7 +283,7 @@ is to help with sanity for these issues, and also to avoid decref's in
 __startcore().
 
 A couple other details: __startcore() sorts the extra increfs, and
-proc_startcore() sorts leaving the old context.  Anytime a __startcore active
+proc_startcore() sorts leaving the old context.  Anytime a __startcore kernel
 message is sent, the sender increfs in advance for the current refcnt.  If that
 was in error, __startcore decrefs.  proc_startcore(), which the last moment
 before we *must* have the cr3/current issues sorted, does the actual check if
@@ -306,12 +306,11 @@ proc_yield() abandons the core / leaves context.
 
 2.3 Other issues:
 ---------------------------
-Note that dealing with interrupting
-processes that are in the kernel is tricky.  There is no true process context, so we can't
-leave a core until the kernel is in a "safe place", i.e. it's state is bundled
-enough that it can be recontinued later.  Calls of this type are not immediate
-active messages, executed at a convenient time (specifically, before we return
-to userspace in proc_startcore().
+Note that dealing with interrupting processes that are in the kernel is tricky.
+There is no true process context, so we can't leave a core until the kernel is
+in a "safe place", i.e. it's state is bundled enough that it can be recontinued
+later.  Calls of this type are routine kernel messages, executed at a convenient
+time (specifically, before we return to userspace in proc_startcore().
 
 This same thing applies to __death messages.  Even though a process is dying, it
 doesn't mean we can just drop whatever the kernel was doing on its behalf.  For
@@ -328,13 +327,13 @@ that needs cleaned up (refcnts that need downed, etc).
 The solution to this is rather simple: don't abandon right away.  That was
 always somewhat the plan for preemption, but was never done for death.  And
 there are several other cases to worry about too.  To enforce this, we expand
-the active messages into a generic work execution message that can be delayed
-or shipped to another core.  These types of messages will not be executed
-immediately on the receiving pcore - instead they are on the queue for "when
-there's nothing else to do in the kernel", which is checked in smp_idle() and
-before returning to userspace in proc_startcore().  Additionally, these active
-messages can also be queued on an alarm queue, delaying their activation as
-part of a generic kernel alarm facility.
+the old "active messages" into a generic work execution message (a kernel
+message) that can be delayed or shipped to another core.  These types of
+messages will not be executed immediately on the receiving pcore - instead they
+are on the queue for "when there's nothing else to do in the kernel", which is
+checked in smp_idle() and before returning to userspace in proc_startcore().
+Additionally, these kernel messages can also be queued on an alarm queue,
+delaying their activation as part of a generic kernel alarm facility.
 
 4. Preemption and Notification Issues:
 ===========================
@@ -342,7 +341,7 @@ part of a generic kernel alarm facility.
 ---------------------------
 Since we go with the model of cores being told what to do, there are issues
 with messages being received in the wrong order.  That is why we have the
-active messages (guaranteed, in-order delivery), with the proc-lock protecting
+kernel messages (guaranteed, in-order delivery), with the proc-lock protecting
 the send order.  However, this is not enough for some rare races.
 
 Local calls can also perform the same tasks as messages (calling
@@ -365,12 +364,12 @@ abort.  This might be sufficient.  This works for death already, since you
 aren't supposed to do anything other than die (and restore any invariants
 first, handled in Section 3).  We'll go with this way.
 
-The other way is to send the work (including the checks) in a self-ipi active
+The other way is to send the work (including the checks) in a self-ipi kernel
 message.  This will guarantee that the message is executed after any existing
-messages (making the a_msg queue the authority for what should happen to a
-core).  The check is also performed later (when the a_msg executes).  There
+messages (making the k_msg queue the authority for what should happen to a
+core).  The check is also performed later (when the k_msg executes).  There
 are a couple issues with this: if we allow the local core to send itself an
-a_msg that could be out of order (meaning it should not be sent, and is only
+k_msg that could be out of order (meaning it should not be sent, and is only
 sent due to ignorance of its sealed fate), AND if we return the core to the
 idle-core-list once its fate is sealed, we need to detect that the message is
 for the wrong process and that the process is in the wrong state.  To do this,
@@ -515,20 +514,20 @@ send a notification.
  
 4.7: Notifs While a Preempt Message is Served
 ---------------------------
-It is possible to have the kernel handling a notification a_msg and to have a
-preempt a_msg in the queue (preempt-served flag is set).  Ultimately, what we
+It is possible to have the kernel handling a notification k_msg and to have a
+preempt k_msg in the queue (preempt-served flag is set).  Ultimately, what we
 want is for the core to be preempted and the notification handler to run on
-the next execution.  Both messages are in the a_msg queue for "a convenient
+the next execution.  Both messages are in the k_msg queue for "a convenient
 time to leave the kernel" (I'll have a better name for that later).  What we
 do is execute the notification handler and jump to userspace.  Since there is
-still an a_msg in the queue (and we self_ipi'd ourselves, it's part of how
-a_msgs work), the IPI will fire and push us right back into the kernel to
+still an k_msg in the queue (and we self_ipi'd ourselves, it's part of how
+k_msgs work), the IPI will fire and push us right back into the kernel to
 execute the preemption, and the notif handler's context will be saved in the
 preempt_tf (ready to go when the vcore gets started again).
 
 We could try to just set the notif_pending flag and ignore the message, but
-that would involve inspecting the queue for the preempt a_msg.  Additionally,
-a preempt a_msg can arrive anyway.  Finally, it's possible to have another
+that would involve inspecting the queue for the preempt k_msg.  Additionally,
+a preempt k_msg can arrive anyway.  Finally, it's possible to have another
 message in the queue between the notif and the preempt, and it gets ugly
 quickly trying to determine what to do.
 
@@ -546,10 +545,10 @@ Also, we don't remove the pcore from the vcoremap, even if it is being
 allocated to another core (the same pcore can exist in two vcoremaps, contrary
 to older statements).  Taking the pcore from the vcoremap would mean some
 non-fate related local calls (sys_get_vcoreid()) will fail, since the vcoreid
-is gone!  Additionally, we don't need a vcoreid in the a_msg (we would have if
+is gone!  Additionally, we don't need a vcoreid in the k_msg (we would have if
 we could not use the vcore/pcoremappings).  There should not be any issues
 with the new process sending messages to the pcore before the core is sorted,
-since a_msgs are delivered in order.
+since k_msgs are delivered in order.
 
 Another tricky part is the seq_ctr used to signal userspace of changes to the
 coremap or num_vcores (coremap_seqctr).  While we may not even need this in the
@@ -566,11 +565,10 @@ value of the seq_ctr before the IPI hits and does the unmapping that the seq_ctr
 protects/advertises.  This is most likely true.  It wouldn't be if the "last IPI
 was sent" flag clears before the IPI actually hit the other core.
 
-
 4.9: Future Broadcast/Messaging Needs
 ---------------------------
-Currently, messaging is serialized.  Broadcast IPIs exist, but the active
-message system is based on adding an a_msg to a list in a pcore's
+Currently, messaging is serialized.  Broadcast IPIs exist, but the kernel
+message system is based on adding an k_msg to a list in a pcore's
 per_cpu_info.  Further the sending of these messages is in a loop.  In the
 future, we would like to have broadcast messaging of some sort (literally a
 broadcast, like the IPIs, and if not that, then a communication tree of
@@ -578,7 +576,7 @@ sorts).
 
 Given those desires, we want to make sure that no message we send needs
 details specific to a pcore (such as the vcoreid running on it, a history
-number, or anything like that).  Thus no a_msg related to process management
+number, or anything like that).  Thus no k_msg related to process management
 should have anything that cannot apply to the entire process.  At this point,
 most just have a struct proc *.  A pcore ought to be able to figure out what
 is happening based on the pcoremap, information in the struct proc, and in the
@@ -586,9 +584,9 @@ preempt struct in procdata.
 
 4.10: Other Things We Thought of but Don't Like
 ---------------------------
-All local fate-related work is sent as a self a_msg, to enforce ordering.
-It doesn't capture the difference between a local call and a remote a_msg.
-The a_msg has already considered state and made its decision.  The local call
+All local fate-related work is sent as a self k_msg, to enforce ordering.
+It doesn't capture the difference between a local call and a remote k_msg.
+The k_msg has already considered state and made its decision.  The local call
 is an attempt.  It is also unnecessary, if we put in enough information to
 make a decision in the proc struct.  Finally, it caused a few other problems
 (like needing to detect arbitrary stale messages).
@@ -610,7 +608,7 @@ and simple.  It is similar to generic messages that have the actual important
 information stored somewhere else (as with allowing broadcasts, with different
 receivers performing slightly different operations).
 
-Synchrony for messages (wanting a response to a preempt a_msg, for example)
+Synchrony for messages (wanting a response to a preempt k_msg, for example)
 sucks.  Just encode the state of impending fate in the proc struct, where it
 belongs.  Additionally, we don't want to hold the proc lock even longer than
 we do now (which is probably too long as it is).  Finally, it breaks a golden
index 3752952..7f45a62 100644 (file)
@@ -51,6 +51,9 @@
 // IPI Interrupt Command Register
 #define LAPIC_IPI_ICR_LOWER                    (LAPIC_BASE + 0x300)
 #define LAPIC_IPI_ICR_UPPER                    (LAPIC_BASE + 0x310)
+// Interrupts being serviced (in-service) and pending (interrupt request reg)
+#define LAPIC_ISR                                      (LAPIC_BASE + 0x170)
+#define LAPIC_IRR                                      (LAPIC_BASE + 0x310)
 
 // PIT (Programmable Interval Timer)
 #define        TIMER_REG_CNTR0 0       /* timer 0 counter port */
@@ -122,6 +125,7 @@ static inline void send_broadcast_ipi(uint8_t vector);
 static inline void send_all_others_ipi(uint8_t vector);
 static inline void send_ipi(uint8_t hw_coreid, uint8_t vector);
 static inline void send_group_ipi(uint8_t hw_groupid, uint8_t vector);
+static inline bool ipi_is_pending(uint8_t vector);
 
 #define mask_lapic_lvt(entry) \
        write_mmreg32(entry, read_mmreg32(entry) | LAPIC_LVT_MASK)
@@ -254,6 +258,13 @@ static inline void send_group_ipi(uint8_t hw_groupid, uint8_t vector)
        lapic_wait_to_send();
 }
 
+/* This works for any interrupt that goes through the LAPIC, but not things like
+ * ExtInts.  To prevent abuse, we'll use it just for IPIs for now. */
+static inline bool ipi_is_pending(uint8_t vector)
+{
+       return (LAPIC_ISR & vector) || (LAPIC_IRR & vector);
+}
+
 /* To change the LAPIC Base (not recommended):
        msr_val = read_msr(IA32_APIC_BASE);
        msr_val = msr_val & ~MSR_APIC_BASE_ADDRESS | 0xfaa00000;
index 0ce45e0..2cd0eab 100644 (file)
@@ -307,5 +307,8 @@ void smp_percpu_init(void)
        else
                per_cpu_info[coreid].gdt = (segdesc_t*)(ROUNDUP(read_esp(), PGSIZE)
                                           - sizeof(segdesc_t)*SEG_COUNT);
-       STAILQ_INIT(&per_cpu_info[coreid].active_msgs);
+       spinlock_init(&per_cpu_info[coreid].immed_amsg_lock);
+       STAILQ_INIT(&per_cpu_info[coreid].immed_amsgs);
+       spinlock_init(&per_cpu_info[coreid].routine_amsg_lock);
+       STAILQ_INIT(&per_cpu_info[coreid].routine_amsgs);
 }
index 4cc609b..95db81c 100644 (file)
@@ -386,74 +386,99 @@ void sysenter_callwrapper(struct trapframe *tf)
        proc_startcore(current, tf);
 }
 
-struct kmem_cache *active_msg_cache;
-void active_msg_init(void)
+struct kmem_cache *kernel_msg_cache;
+void kernel_msg_init(void)
 {
-       active_msg_cache = kmem_cache_create("active_msgs",
-                          sizeof(struct active_message), HW_CACHE_ALIGN, 0, 0, 0);
+       kernel_msg_cache = kmem_cache_create("kernel_msgs",
+                          sizeof(struct kernel_message), HW_CACHE_ALIGN, 0, 0, 0);
 }
 
-uint32_t send_active_message(uint32_t dst, amr_t pc,
-                             TV(a0t) arg0, TV(a1t) arg1, TV(a2t) arg2)
+uint32_t send_kernel_message(uint32_t dst, amr_t pc, TV(a0t) arg0, TV(a1t) arg1,
+                             TV(a2t) arg2, int type)
 {
-       active_message_t *a_msg;
+       kernel_message_t *k_msg;
        assert(pc);
        // note this will be freed on the destination core
-       a_msg = (active_message_t *CT(1))TC(kmem_cache_alloc(active_msg_cache, 0));
-       a_msg->srcid = core_id();
-       a_msg->pc = pc;
-       a_msg->arg0 = arg0;
-       a_msg->arg1 = arg1;
-       a_msg->arg2 = arg2;
-       spin_lock_irqsave(&per_cpu_info[dst].amsg_lock);
-       STAILQ_INSERT_TAIL(&per_cpu_info[dst].active_msgs, a_msg, link);
-       spin_unlock_irqsave(&per_cpu_info[dst].amsg_lock);
+       k_msg = (kernel_message_t *CT(1))TC(kmem_cache_alloc(kernel_msg_cache, 0));
+       k_msg->srcid = core_id();
+       k_msg->pc = pc;
+       k_msg->arg0 = arg0;
+       k_msg->arg1 = arg1;
+       k_msg->arg2 = arg2;
+       switch (type) {
+               case AMSG_IMMEDIATE:
+                       spin_lock_irqsave(&per_cpu_info[dst].immed_amsg_lock);
+                       STAILQ_INSERT_TAIL(&per_cpu_info[dst].immed_amsgs, k_msg, link);
+                       spin_unlock_irqsave(&per_cpu_info[dst].immed_amsg_lock);
+                       break;
+               case AMSG_ROUTINE:
+                       spin_lock_irqsave(&per_cpu_info[dst].routine_amsg_lock);
+                       STAILQ_INSERT_TAIL(&per_cpu_info[dst].routine_amsgs, k_msg, link);
+                       spin_unlock_irqsave(&per_cpu_info[dst].routine_amsg_lock);
+                       break;
+               default:
+                       panic("Unknown type of kernel message!");
+       }
        // since we touched memory the other core will touch (the lock), we don't
        // need an wmb_f()
-       send_ipi(get_hw_coreid(dst), I_ACTIVE_MSG);
+       send_ipi(get_hw_coreid(dst), I_KERNEL_MSG);
        return 0;
 }
 
-/* Active message handler.  We don't want to block other AMs from coming in, so
- * we'll copy out the message and let go of the lock.  This won't return until
- * all pending AMs are executed.  If the PC is 0, then this was an extra IPI and
- * we already handled the message (or someone is sending IPIs without loading
- * the active message...)
+/* Helper function.  Returns 0 if the list was empty. */
+static kernel_message_t *get_next_amsg(struct kernel_msg_list *list_head,
+                                       spinlock_t *list_lock)
+{
+       kernel_message_t *k_msg;
+       spin_lock_irqsave(list_lock);
+       k_msg = STAILQ_FIRST(list_head);
+       if (k_msg)
+               STAILQ_REMOVE_HEAD(list_head, link);
+       spin_unlock_irqsave(list_lock);
+       return k_msg;
+}
+
+/* Kernel message handler.  Extensive documentation is in
+ * Documentation/kernel_messages.txt.
+ *
+ * In general: this processes immediate messages, then routine messages.
+ * Routine messages might not return (__startcore, etc), so we need to be
+ * careful about a few things.
+ *
  * Note that all of this happens from interrupt context, and interrupts are
  * currently disabled for this gate.  Interrupts need to be disabled so that the
- * self-ipi doesn't preempt the execution of this active message. */
-void __active_message(trapframe_t *tf)
+ * self-ipi doesn't preempt the execution of this kernel message. */
+void __kernel_message(struct trapframe *tf)
 {
-       per_cpu_info_t RO*myinfo = &per_cpu_info[core_id()];
-       active_message_t my_msg, *a_msg;
+       per_cpu_info_t *myinfo = &per_cpu_info[core_id()];
+       kernel_message_t msg_cp, *k_msg;
 
        lapic_send_eoi();
        while (1) { // will break out when there are no more messages
-               /* Get the message */
-               spin_lock_irqsave(&myinfo->amsg_lock);
-               a_msg = STAILQ_FIRST(&myinfo->active_msgs);
-               /* No messages to execute, so break out, etc. */
-               if (!a_msg) {
-                       spin_unlock_irqsave(&myinfo->amsg_lock);
-                       return;
+               /* Try to get an immediate message.  Exec and free it. */
+               k_msg = get_next_amsg(&myinfo->immed_amsgs, &myinfo->immed_amsg_lock);
+               if (k_msg) {
+                       assert(k_msg->pc);
+                       k_msg->pc(tf, k_msg->srcid, k_msg->arg0, k_msg->arg1, k_msg->arg2);
+                       kmem_cache_free(kernel_msg_cache, (void*)k_msg);
+               } else { // no immediate, might be a routine
+                       if (in_kernel(tf))
+                               return; // don't execute routine msgs if we were in the kernel
+                       k_msg = get_next_amsg(&myinfo->routine_amsgs,
+                                             &myinfo->routine_amsg_lock);
+                       if (!k_msg) // no routines either
+                               return;
+                       /* copy in, and then free, in case we don't return */
+                       msg_cp = *k_msg;
+                       kmem_cache_free(kernel_msg_cache, (void*)k_msg);
+                       /* make sure an IPI is pending if we have more work */
+                       /* techincally, we don't need to lock when checking */
+                       if (!STAILQ_EMPTY(&myinfo->routine_amsgs) &&
+                              !ipi_is_pending(I_KERNEL_MSG))
+                               send_self_ipi(I_KERNEL_MSG);
+                       /* Execute the kernel message */
+                       assert(msg_cp.pc);
+                       msg_cp.pc(tf, msg_cp.srcid, msg_cp.arg0, msg_cp.arg1, msg_cp.arg2);
                }
-               STAILQ_REMOVE_HEAD(&myinfo->active_msgs, link);
-               spin_unlock_irqsave(&myinfo->amsg_lock);
-               // copy in, and then free, in case we don't return
-               my_msg = *a_msg;
-               kmem_cache_free(active_msg_cache, (void *CT(1))TC(a_msg));
-               assert(my_msg.pc);
-               /* In case the function doesn't return (which is common: __startcore,
-                * __death, etc), there is a chance we could lose an amsg.  We can only
-                * have up to two interrupts outstanding, and if we never return, we
-                * never deal with any other amsgs.  This extra IPI hurts performance
-                * but is only necessary if there is another outstanding message in the
-                * buffer, but makes sure we never miss out on an amsg. */
-               spin_lock_irqsave(&myinfo->amsg_lock);
-               if (!STAILQ_EMPTY(&myinfo->active_msgs))
-                       send_self_ipi(I_ACTIVE_MSG);
-               spin_unlock_irqsave(&myinfo->amsg_lock);
-               /* Execute the active message */
-               my_msg.pc(tf, my_msg.srcid, my_msg.arg0, my_msg.arg1, my_msg.arg2);
        }
 }
index 41fcad9..42e6fb2 100644 (file)
 #define I_SMP_CALL4    0xf4
 #define I_SMP_CALL_LAST I_SMP_CALL4
 /* Direct/Hardwired IPIs.  Hardwired in trapentry.S */
-#define I_ACTIVE_MSG   255
-
-/* Number of active messages available per core (arbitrary) */
-#define NUM_ACTIVE_MESSAGES 5
-
+#define I_KERNEL_MSG   255
 
 #ifndef __ASSEMBLER__
 
@@ -71,6 +67,12 @@ static inline void set_errno(trapframe_t* tf, uint32_t errno)
        tf->tf_regs.reg_esi = errno;
 }
 
+/* Determines if the given TF was in the kernel or not. */
+static inline bool in_kernel(struct trapframe *tf)
+{
+       return (tf->tf_cs & ~3) == GD_KT;
+}
+
 #endif /* !__ASSEMBLER__ */
 
 #endif /* !ROS_INC_ARCH_TRAP_H */
index 3e95efb..3693511 100644 (file)
@@ -171,7 +171,7 @@ IRQ_HANDLER(IRQ219, 251)
 IRQ_HANDLER(IRQ220, 252)
 IRQ_HANDLER(IRQ221, 253)
 IRQ_HANDLER(IRQ222, 254)
-IRQ_HANDLER_SPEC(IRQ223, I_ACTIVE_MSG, __active_message)
+IRQ_HANDLER_SPEC(IRQ223, I_KERNEL_MSG, __kernel_message)
 
 /* Technically, these HANDLER entries do not need to be in numeric order */
 TRAPHANDLER_NOEC(ISR_syscall, T_SYSCALL)
index 347b1b2..a1a9198 100644 (file)
@@ -19,8 +19,8 @@ static_asserts_can_go_here()
 {
        static_assert(SIZEOF_TRAPFRAME_T == sizeof(trapframe_t));
        static_assert(SIZEOF_TRAPFRAME_T % 8 == 0);
-       static_assert(SIZEOF_ACTIVE_MESSAGE_T == sizeof(active_message_t));
-       static_assert(SIZEOF_ACTIVE_MESSAGE_T % 8 == 0);
+       static_assert(SIZEOF_KERNEL_MESSAGE_T == sizeof(kernel_message_t));
+       static_assert(SIZEOF_KERNEL_MESSAGE_T % 8 == 0);
        static_assert(offsetof(env_t,env_tf) % 8 == 0);
        static_assert(offsetof(env_t,env_ancillary_state) % 8 == 0);
 }
index 631396f..8b7f949 100644 (file)
@@ -94,13 +94,13 @@ int smp_call_function_all(isr_t handler, void* data,
                if(i == core_id())
                        continue;
 
-               send_active_message(i,(amr_t)smp_call_wrapper,
-                                         handler, wrapper, data);
+               send_kernel_message(i,(amr_t)smp_call_wrapper,
+                                         handler, wrapper, data, AMSG_IMMEDIATE);
        }
 
        // send to me
-       send_active_message(core_id(),(amr_t)smp_call_wrapper,
-                                 handler,wrapper,data);
+       send_kernel_message(core_id(),(amr_t)smp_call_wrapper,
+                                 handler,wrapper,data, AMSG_IMMEDIATE);
 
        cpu_relax(); // wait to get the interrupt
 
@@ -124,8 +124,8 @@ int smp_call_function_single(uint32_t dest, isr_t handler, void* data,
 
        enable_irqsave(&state);
 
-       send_active_message(dest,(amr_t)smp_call_wrapper,
-                                 handler,wrapper,data);
+       send_kernel_message(dest,(amr_t)smp_call_wrapper,
+                                 handler,wrapper,data, AMSG_IMMEDIATE);
 
        cpu_relax(); // wait to get the interrupt, if it's to this core
 
@@ -150,5 +150,8 @@ int smp_call_wait(handler_wrapper_t* wrapper)
 void smp_percpu_init(void)
 {
        uint32_t coreid = core_id();
-       STAILQ_INIT(&per_cpu_info[coreid].active_msgs);
+       spinlock_init(&per_cpu_info[coreid].immed_amsg_lock);
+       STAILQ_INIT(&per_cpu_info[coreid].immed_amsgs);
+       spinlock_init(&per_cpu_info[coreid].routine_amsg_lock);
+       STAILQ_INIT(&per_cpu_info[coreid].routine_amsgs);
 }
index 2c951a0..9a8e6ad 100644 (file)
 #pragma nodeputy
 #endif
 
-spinlock_t active_message_buf_busy[MAX_NUM_CPUS] = {SPINLOCK_INITIALIZER};
-active_message_t active_message_buf[MAX_NUM_CPUS];
+spinlock_t kernel_message_buf_busy[MAX_NUM_CPUS] = {SPINLOCK_INITIALIZER};
+kernel_message_t kernel_message_buf[MAX_NUM_CPUS];
 
-uint32_t send_active_message(uint32_t dst, amr_t pc,
-                             TV(a0t) arg0, TV(a1t) arg1, TV(a2t) arg2)
+uint32_t send_kernel_message(uint32_t dst, amr_t pc,
+                             TV(a0t) arg0, TV(a1t) arg1, TV(a2t) arg2, int type)
 {
-       if(dst >= num_cpus || spin_trylock(&active_message_buf_busy[dst]))
+       /* TODO: need to merge with x86 for one unified messaging (based on IPIs).
+        * you can temporarily get by with ignoring the distinction between routine
+        * and urgent, but certain races will ruin the system.  also note that no
+        * code is able to handle a failure of this function. */
+       if(dst >= num_cpus || spin_trylock(&kernel_message_buf_busy[dst]))
                return -1;
 
-       active_message_buf[dst].srcid = core_id();
-       active_message_buf[dst].pc = pc;
-       active_message_buf[dst].arg0 = arg0;
-       active_message_buf[dst].arg1 = arg1;
-       active_message_buf[dst].arg2 = arg2;
+       kernel_message_buf[dst].srcid = core_id();
+       kernel_message_buf[dst].pc = pc;
+       kernel_message_buf[dst].arg0 = arg0;
+       kernel_message_buf[dst].arg1 = arg1;
+       kernel_message_buf[dst].arg2 = arg2;
 
        if(send_ipi(dst))
        {
-               spin_unlock(&active_message_buf_busy[dst]);
+               spin_unlock(&kernel_message_buf_busy[dst]);
                return -1;
        }
 
@@ -138,9 +142,9 @@ get_trapname(uint8_t tt, char buf[TRAPNAME_MAX])
 void
 handle_ipi(trapframe_t* state)
 {
-       active_message_t m;
-       m = active_message_buf[core_id()];
-       spin_unlock(&active_message_buf_busy[core_id()]);
+       kernel_message_t m;
+       m = kernel_message_buf[core_id()];
+       spin_unlock(&kernel_message_buf_busy[core_id()]);
 
        uint32_t src = m.srcid;
        TV(a0t) a0 = m.arg0;
@@ -333,9 +337,9 @@ handle_breakpoint(trapframe_t* state)
        env_pop_tf(state);
 }
 
-struct kmem_cache *active_msg_cache;
-void active_msg_init(void)
+struct kmem_cache *kernel_msg_cache;
+void kernel_msg_init(void)
 {
-       active_msg_cache = kmem_cache_create("active_msgs",
-                          sizeof(struct active_message), HW_CACHE_ALIGN, 0, 0, 0);
+       kernel_msg_cache = kmem_cache_create("kernel_msgs",
+                          sizeof(struct kernel_message), HW_CACHE_ALIGN, 0, 0, 0);
 }
index 668f388..c1352e8 100644 (file)
@@ -2,7 +2,7 @@
 #define ROS_INC_ARCH_TRAP_H
 
 #define SIZEOF_TRAPFRAME_T     0xB0
-#define SIZEOF_ACTIVE_MESSAGE_T        0x18
+#define SIZEOF_KERNEL_MESSAGE_T        0x18
 
 #ifndef __ASSEMBLER__
 
@@ -25,6 +25,13 @@ static inline void set_errno(trapframe_t* tf, uint32_t errno)
        tf->gpr[9] = errno;
 }
 
+/* TODO: Need to determine if the TF was in the kernel. */
+static inline bool in_kernel(struct trapframe *tf)
+{
+       static_assert(0);
+       return LIES;
+}
+
 #endif /* !__ASSEMBLER__ */
 
 #endif /* !ROS_INC_ARCH_TRAP_H */
index 3643772..e704127 100644 (file)
@@ -137,7 +137,7 @@ void proc_decref(struct proc *SAFE p, size_t count);
 
 void abandon_core(void);
 
-/* Active message handlers for process management */
+/* Kernel message handlers for process management */
 #ifdef __IVY__
 void __startcore(trapframe_t *tf, uint32_t srcid, struct proc *CT(1) a0,
                  trapframe_t *CT(1) a1, void *SNT a2);
index 282dfed..0491005 100644 (file)
@@ -65,7 +65,7 @@ struct preempt_data {
        // TODO: move to procinfo!
        uint64_t                                preempt_pending;
        bool                                    notif_enabled;          /* vcore is willing to receive*/
-       bool                                    notif_pending;          /* notif a_msg on the way */
+       bool                                    notif_pending;          /* notif k_msg on the way */
        seq_ctr_t                               preempt_tf_valid;
        uint8_t                                 notif_bmask[(NR_PERCORE_EVENTS - 1) / 8 + 1];
        struct notif_event              notif_events[NR_PERCORE_EVENTS];
index 1427f45..a0f2b35 100644 (file)
@@ -38,8 +38,10 @@ struct per_cpu_info {
        segdesc_t *gdt;
 #endif
 
-       spinlock_t amsg_lock;
-       struct active_msg_list NTPTV(a0t) NTPTV(a1t) NTPTV(a2t) active_msgs;
+       spinlock_t immed_amsg_lock;
+       struct kernel_msg_list NTPTV(a0t) NTPTV(a1t) NTPTV(a2t) immed_amsgs;
+       spinlock_t routine_amsg_lock;
+       struct kernel_msg_list NTPTV(a0t) NTPTV(a1t) NTPTV(a2t) routine_amsgs;
 }__attribute__((aligned(HW_CACHE_ALIGN)));
 
 typedef struct per_cpu_info NTPTV(t) NTPTV(a0t) NTPTV(a1t) NTPTV(a2t) per_cpu_info_t;
index 66fff29..36543ac 100644 (file)
@@ -23,7 +23,7 @@ void test_smp_call_functions(void);
 void test_lapic_status_bit(void);
 void test_run_measurements(uint32_t job_num);
 void test_circ_buffer(void);
-void test_active_messages(void);
+void test_kernel_messages(void);
 void test_slab(void);
 void test_kmalloc(void);
 void test_hashtable(void);
index 00ad179..802fdb7 100644 (file)
@@ -36,27 +36,31 @@ void ( page_fault_handler)(trapframe_t *tf);
 void sysenter_init(void);
 extern void sysenter_handler();
 
-/* Active messages.  Each arch implements them in their own way.  Both should be
+/* Kernel messages.  Each arch implements them in their own way.  Both should be
  * guaranteeing in-order delivery.  Kept here in trap.h, since sparc is using
- * trap.h for AMs
+ * trap.h for KMs.  Eventually, both arches will use the same implementation.
  *
  * These are different (for now) than the smp_calls in smp.h, since
- * they will be executed immediately, and in the order in which they are sent.
- * smp_calls are currently not run in order, and if they put things on the
- * workqueue, they don't get run until smp_idle (for now).
+ * they will be executed immediately (for urgent messages), and in the order in
+ * which they are sent.  smp_calls are currently not run in order, and if they
+ * put things on the workqueue, they don't get run until smp_idle (for now).
+ *
+ * Eventually, smp_call and the workqueue will be replaced by these.
  *
  * Also, a big difference is that smp_calls can use the same message (registered
- * in the interrupt_handlers[] for x86) for every recipient, but the active
+ * in the interrupt_handlers[] for x86) for every recipient, but the kernel
  * messages require a unique message.  Also for now, but it might be like that
- * for a while on x86. */
+ * for a while on x86 (til we have a broadcast). */
 
-void active_msg_init(void);
+#define AMSG_IMMEDIATE                         1
+#define AMSG_ROUTINE                   2
+void kernel_msg_init(void);
 typedef void (*amr_t)(trapframe_t* tf, uint32_t srcid,
                       TV(a0t) a0, TV(a1t) a1, TV(a2t) a2);
 
-struct active_message
+struct kernel_message
 {
-       STAILQ_ENTRY(active_message NTPTV(a0t) NTPTV(a1t) NTPTV(a2t))
+       STAILQ_ENTRY(kernel_message NTPTV(a0t) NTPTV(a1t) NTPTV(a2t))
                NTPTV(a0t) NTPTV(a1t) NTPTV(a2t) link;
        uint32_t srcid;
        amr_t pc;
@@ -64,10 +68,10 @@ struct active_message
        TV(a1t) arg1;
        TV(a2t) arg2;
 };
-STAILQ_HEAD(active_msg_list, active_message NTPTV(a0t) NTPTV(a1t) NTPTV(a2t));
-typedef struct active_message NTPTV(a0t) NTPTV(a1t) NTPTV(a2t) active_message_t;
+STAILQ_HEAD(kernel_msg_list, kernel_message NTPTV(a0t) NTPTV(a1t) NTPTV(a2t));
+typedef struct kernel_message NTPTV(a0t) NTPTV(a1t) NTPTV(a2t) kernel_message_t;
 
-uint32_t send_active_message(uint32_t dst, amr_t pc,
-                             TV(a0t) arg0, TV(a1t) arg1, TV(a2t) arg2);
+uint32_t send_kernel_message(uint32_t dst, amr_t pc, TV(a0t) arg0, TV(a1t) arg1,
+                             TV(a2t) arg2, int type);
 
 #endif /* ROS_KERN_TRAP_H */
index a40e892..7781399 100644 (file)
@@ -284,7 +284,8 @@ void appserver_die(int code)
        int i;
        for(i = 0; i < num_cpus; i++)
                if(i != core_id())
-                       while(send_active_message(i,(amr_t)&__diediedie,(void*)code,0,0));
+                       while(send_kernel_message(i,(amr_t)&__diediedie,(void*)code,0,0,
+                                                 AMSG_IMMEDIATE));
 
        // just in case.
        __diediedie(0,0,code,0,0);
index 25b7c3f..889974a 100644 (file)
@@ -78,7 +78,7 @@ void kernel_init(multiboot_info_t *mboot_info)
        page_check();
 
        idt_init();
-       active_msg_init();
+       kernel_msg_init();
        sysenter_init();
        timer_init();
        
index 4f0e1f0..f46d1cc 100644 (file)
@@ -400,7 +400,7 @@ void proc_run(struct proc *p)
                        break;
                case (PROC_RUNNABLE_M):
                        /* vcoremap[i] holds the coreid of the physical core allocated to
-                        * this process.  It is set outside proc_run.  For the active
+                        * this process.  It is set outside proc_run.  For the kernel
                         * message, a0 = struct proc*, a1 = struct trapframe*.   */
                        if (p->procinfo->num_vcores) {
                                __proc_set_state(p, PROC_RUNNING_M);
@@ -423,8 +423,9 @@ void proc_run(struct proc *p)
                                for (int i = 1; i < p->procinfo->num_vcores; i++)
                                        assert(!p->procinfo->vcoremap[i].tf_to_run);
                                for (int i = 0; i < p->procinfo->num_vcores; i++)
-                                       send_active_message(p->procinfo->vcoremap[i].pcoreid,
-                                                           (void *)__startcore, (void *)p, 0, 0);
+                                       send_kernel_message(p->procinfo->vcoremap[i].pcoreid,
+                                                           (void *)__startcore, (void *)p, 0, 0,
+                                                           AMSG_IMMEDIATE);
                        } else {
                                warn("Tried to proc_run() an _M with no vcores!");
                        }
@@ -575,8 +576,9 @@ void proc_destroy(struct proc *p)
                                current = NULL;
                        }
                        #endif
-                       send_active_message(p->procinfo->vcoremap[0].pcoreid, __death,
-                                          (void *SNT)0, (void *SNT)0, (void *SNT)0);
+                       send_kernel_message(p->procinfo->vcoremap[0].pcoreid, __death,
+                                          (void *SNT)0, (void *SNT)0, (void *SNT)0,
+                                          AMSG_IMMEDIATE);
                        __seq_start_write(&p->procinfo->coremap_seqctr);
                        // TODO: might need to sort num_vcores too later (VC#)
                        /* vcore is unmapped on the receive side */
@@ -810,7 +812,8 @@ bool __proc_give_cores(struct proc *SAFE p, uint32_t *pcorelist, size_t num)
                                p->procinfo->num_vcores++;
                                /* should be a fresh core */
                                assert(!p->procinfo->vcoremap[i].tf_to_run);
-                               send_active_message(pcorelist[i], __startcore, p, 0, 0);
+                               send_kernel_message(pcorelist[i], __startcore, p, 0, 0,
+                                                   AMSG_IMMEDIATE);
                                if (pcorelist[i] == core_id())
                                        self_ipi_pending = TRUE;
                        }
@@ -842,7 +845,7 @@ bool __proc_set_allcores(struct proc *SAFE p, uint32_t *pcorelist,
 }
 
 /* Takes from process p the num cores listed in pcorelist, using the given
- * message for the active message (__death, __preempt, etc).  Like the others
+ * message for the kernel message (__death, __preempt, etc).  Like the others
  * in this function group, bool signals whether or not an IPI is pending.
  *
  * WARNING: You must hold the proc_lock before calling this! */
@@ -876,7 +879,8 @@ bool __proc_take_cores(struct proc *SAFE p, uint32_t *pcorelist,
                if (message) {
                        if (pcoreid == core_id())
                                self_ipi_pending = TRUE;
-                       send_active_message(pcoreid, message, arg0, arg1, arg2);
+                       send_kernel_message(pcoreid, message, arg0, arg1, arg2,
+                                           AMSG_IMMEDIATE);
                } else {
                        /* if there was a msg, the vcore is unmapped on the receive side.
                         * o/w, we need to do it here. */
@@ -924,7 +928,8 @@ bool __proc_take_allcores(struct proc *SAFE p, amr_t message,
                if (message) {
                        if (pcoreid == core_id())
                                self_ipi_pending = TRUE;
-                       send_active_message(pcoreid, message, arg0, arg1, arg2);
+                       send_kernel_message(pcoreid, message, arg0, arg1, arg2,
+                                           AMSG_IMMEDIATE);
                } else {
                        /* if there was a msg, the vcore is unmapped on the receive side.
                         * o/w, we need to do it here. */
@@ -1010,7 +1015,7 @@ void proc_decref(struct proc *p, size_t count)
                panic("Too many decrefs!");
 }
 
-/* Active message handler to start a process's context on this core.  Tightly
+/* Kernel message handler to start a process's context on this core.  Tightly
  * coupled with proc_run() */
 void __startcore(trapframe_t *tf, uint32_t srcid, void *a0, void *a1, void *a2)
 {
@@ -1050,7 +1055,7 @@ void abandon_core(void)
        smp_idle();
 }
 
-/* Active message handler to clean up the core when a process is dying.
+/* Kernel message handler to clean up the core when a process is dying.
  * Note this leaves no trace of what was running.
  * It's okay if death comes to a core that's already idling and has no current.
  * It could happen if a process decref'd before proc_startcore could incref. */
index f5a9c81..8967c02 100644 (file)
@@ -807,44 +807,44 @@ void test_circ_buffer(void)
        return;
 }
 
-#ifdef __IVY__
-void test_am_handler(trapframe_t* tf, uint32_t srcid, uint32_t a0, uint32_t a1,
-                     uint32_t a2)
-#else
-void test_am_handler(trapframe_t* tf, uint32_t srcid, void * a0, void * a1,
-                     void * a2)
-#endif
+void test_km_handler(trapframe_t* tf, uint32_t srcid, void *a0, void *a1,
+                     void *a2)
 {
-       printk("Received AM on core %d from core %d: arg0= 0x%08x, arg1 = "
+       printk("Received KM on core %d from core %d: arg0= 0x%08x, arg1 = "
               "0x%08x, arg2 = 0x%08x\n", core_id(), srcid, a0, a1, a2);
        return;
 }
 
-void test_active_messages(void)
+void test_kernel_messages(void)
 {
-       // basic tests, make sure we can handle a wraparound and that the error
-       // messages work.
-       printk("sending NUM_ACTIVE_MESSAGES to core 1, sending (#,deadbeef,0)\n");
-       for (int i = 0; i < NUM_ACTIVE_MESSAGES; i++)
-#ifdef __IVY__
-               while (send_active_message(1, test_am_handler, i, 0xdeadbeef, 0))
-                       cpu_relax();
-#else
-               while (send_active_message(1, test_am_handler, (void *)i,
-                                          (void *)0xdeadbeef, (void *)0))
-                       cpu_relax();
-#endif
+       printk("Testing Kernel Messages\n");
+       /* Testing sending multiples, sending different types, alternating, and
+        * precendence (the immediates should trump the others) */
+       printk("sending 5 IMMED to core 1, sending (#,deadbeef,0)\n");
+       for (int i = 0; i < 5; i++)
+               send_kernel_message(1, test_km_handler, (void*)i, (void*)0xdeadbeef,
+                                   (void*)0, AMSG_IMMEDIATE);
        udelay(5000000);
-       printk("sending 2*NUM_ACTIVE_MESSAGES to core 1, sending (#,cafebabe,0)\n");
-       for (int i = 0; i < 2*NUM_ACTIVE_MESSAGES; i++)
-#ifdef __IVY__
-               while (send_active_message(1, test_am_handler, i, 0xdeadbeef, 0))
-                       cpu_relax();
-#else
-               while (send_active_message(1, test_am_handler, (void *)i,
-                                          (void *)0xdeadbeef, (void *)0))
-                       cpu_relax();
-#endif
+       printk("sending 5 routine to core 1, sending (#,cafebabe,0)\n");
+       for (int i = 0; i < 5; i++)
+               send_kernel_message(1, test_km_handler, (void*)i, (void*)0xcafebabe,
+                                   (void*)0, AMSG_ROUTINE);
+       udelay(5000000);
+       printk("sending 10 routine and 3 immediate to core 2\n");
+       for (int i = 0; i < 10; i++)
+               send_kernel_message(2, test_km_handler, (void*)i, (void*)0xcafebabe,
+                                   (void*)0, AMSG_ROUTINE);
+       for (int i = 0; i < 3; i++)
+               send_kernel_message(2, test_km_handler, (void*)i, (void*)0xdeadbeef,
+                                   (void*)0, AMSG_IMMEDIATE);
+       udelay(5000000);
+       printk("sending 5 ea alternating to core 2\n");
+       for (int i = 0; i < 5; i++) {
+               send_kernel_message(2, test_km_handler, (void*)i, (void*)0xdeadbeef,
+                                   (void*)0, AMSG_IMMEDIATE);
+               send_kernel_message(2, test_km_handler, (void*)i, (void*)0xcafebabe,
+                                   (void*)0, AMSG_ROUTINE);
+       }
        udelay(5000000);
        return;
 }