67266d6674d2183eabe7df7f950adf047e41d5f7
[akaros.git] / kern / src / trap.c
1 /* Copyright (c) 2012 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Arch-independent trap handling and kernel messaging */
6
7 #include <arch/arch.h>
8 #include <smp.h>
9 #include <trap.h>
10 #include <stdio.h>
11 #include <slab.h>
12 #include <assert.h>
13 #include <kdebug.h>
14 #include <kmalloc.h>
15
16 struct kmem_cache *kernel_msg_cache;
17
18 void kernel_msg_init(void)
19 {
20         kernel_msg_cache = kmem_cache_create("kernel_msgs",
21                            sizeof(struct kernel_message), ARCH_CL_SIZE, 0, 0, 0);
22 }
23
24 uint32_t send_kernel_message(uint32_t dst, amr_t pc, long arg0, long arg1,
25                              long arg2, int type)
26 {
27         kernel_message_t *k_msg;
28         assert(pc);
29         // note this will be freed on the destination core
30         k_msg = kmem_cache_alloc(kernel_msg_cache, 0);
31         k_msg->srcid = core_id();
32         k_msg->dstid = dst;
33         k_msg->pc = pc;
34         k_msg->arg0 = arg0;
35         k_msg->arg1 = arg1;
36         k_msg->arg2 = arg2;
37         switch (type) {
38                 case KMSG_IMMEDIATE:
39                         spin_lock_irqsave(&per_cpu_info[dst].immed_amsg_lock);
40                         STAILQ_INSERT_TAIL(&per_cpu_info[dst].immed_amsgs, k_msg, link);
41                         spin_unlock_irqsave(&per_cpu_info[dst].immed_amsg_lock);
42                         break;
43                 case KMSG_ROUTINE:
44                         spin_lock_irqsave(&per_cpu_info[dst].routine_amsg_lock);
45                         STAILQ_INSERT_TAIL(&per_cpu_info[dst].routine_amsgs, k_msg, link);
46                         spin_unlock_irqsave(&per_cpu_info[dst].routine_amsg_lock);
47                         break;
48                 default:
49                         panic("Unknown type of kernel message!");
50         }
51         /* since we touched memory the other core will touch (the lock), we don't
52          * need an wmb_f() */
53         /* if we're sending a routine message locally, we don't want/need an IPI */
54         if ((dst != k_msg->srcid) || (type == KMSG_IMMEDIATE))
55                 send_ipi(dst, I_KERNEL_MSG);
56         return 0;
57 }
58
59 /* Kernel message IPI/IRQ handler.
60  *
61  * This processes immediate messages, and that's it (it used to handle routines
62  * too, if it came in from userspace).  Routine messages will get processed when
63  * the kernel has a chance (right before popping to userspace or in smp_idle
64  * before halting).
65  *
66  * Note that all of this happens from interrupt context, and interrupts are
67  * disabled. */
68 void handle_kmsg_ipi(struct hw_trapframe *hw_tf, void *data)
69 {
70         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
71         struct kernel_message *kmsg_i, *temp;
72         assert(!irq_is_enabled());
73         /* Avoid locking if the list appears empty (lockless peak is okay) */
74         if (STAILQ_EMPTY(&pcpui->immed_amsgs))
75                 return;
76         /* The lock serves as a cmb to force a re-read of the head of the list */
77         spin_lock(&pcpui->immed_amsg_lock);
78         STAILQ_FOREACH_SAFE(kmsg_i, &pcpui->immed_amsgs, link, temp) {
79                 pcpui_trace_kmsg(pcpui, (uintptr_t)kmsg_i->pc);
80                 kmsg_i->pc(kmsg_i->srcid, kmsg_i->arg0, kmsg_i->arg1, kmsg_i->arg2);
81                 STAILQ_REMOVE(&pcpui->immed_amsgs, kmsg_i, kernel_message, link);
82                 kmem_cache_free(kernel_msg_cache, (void*)kmsg_i);
83         }
84         spin_unlock(&pcpui->immed_amsg_lock);
85 }
86
87 /* Helper function, gets the next routine KMSG (RKM).  Returns 0 if the list was
88  * empty. */
89 static kernel_message_t *get_next_rkmsg(struct per_cpu_info *pcpui)
90 {
91         struct kernel_message *kmsg;
92         /* Avoid locking if the list appears empty (lockless peak is okay) */
93         if (STAILQ_EMPTY(&pcpui->routine_amsgs))
94                 return 0;
95         /* The lock serves as a cmb to force a re-read of the head of the list */
96         spin_lock(&pcpui->routine_amsg_lock);
97         kmsg = STAILQ_FIRST(&pcpui->routine_amsgs);
98         if (kmsg)
99                 STAILQ_REMOVE_HEAD(&pcpui->routine_amsgs, link);
100         spin_unlock(&pcpui->routine_amsg_lock);
101         return kmsg;
102 }
103
104 /* Runs routine kernel messages.  This might not return.  In the past, this
105  * would also run immediate messages, but this is unnecessary.  Immediates will
106  * run whenever we reenable IRQs.  We could have some sort of ordering or
107  * guarantees between KMSG classes, but that's not particularly useful at this
108  * point.
109  *
110  * Note this runs from normal context, with interruptes disabled.  However, a
111  * particular RKM could enable interrupts - for instance __launch_kthread() will
112  * restore an old kthread that may have had IRQs on. */
113 void process_routine_kmsg(void)
114 {
115         uint32_t pcoreid = core_id();
116         struct per_cpu_info *pcpui = &per_cpu_info[pcoreid];
117         struct kernel_message msg_cp, *kmsg;
118
119         /* Important that callers have IRQs disabled.  When sending cross-core RKMs,
120          * the IPI is used to keep the core from going to sleep - even though RKMs
121          * aren't handled in the kmsg handler.  Check smp_idle() for more info. */
122         assert(!irq_is_enabled());
123         while ((kmsg = get_next_rkmsg(pcpui))) {
124                 /* Copy in, and then free, in case we don't return */
125                 msg_cp = *kmsg;
126                 kmem_cache_free(kernel_msg_cache, (void*)kmsg);
127                 assert(msg_cp.dstid == pcoreid);        /* caught a brutal bug with this */
128                 set_rkmsg(pcpui);                                       /* we're now in early RKM ctx */
129                 /* The kmsg could block.  If it does, we want the kthread code to know
130                  * it's not running on behalf of a process, and we're actually spawning
131                  * a kernel task.  While we do have a syscall that does work in an RKM
132                  * (change_to), it's not really the rest of the syscall context. */
133                 pcpui->cur_kthread->is_ktask = TRUE;
134                 pcpui_trace_kmsg(pcpui, (uintptr_t)msg_cp.pc);
135                 msg_cp.pc(msg_cp.srcid, msg_cp.arg0, msg_cp.arg1, msg_cp.arg2);
136                 /* And if we make it back, be sure to unset this.  If we never return,
137                  * but the kthread exits via some other way (smp_idle()), then
138                  * smp_idle() will deal with the flag.  The default state is "off".  For
139                  * an example of an RKM that does this, check out the
140                  * monitor->mon_bin_run.  Finally, if the kthread gets swapped out of
141                  * pcpui, such as in __launch_kthread(), the next time the kthread is
142                  * reused, is_ktask will be reset. */
143                 pcpui->cur_kthread->is_ktask = FALSE;
144                 /* If we aren't still in early RKM, it is because the KMSG blocked
145                  * (thus leaving early RKM, finishing in default context) and then
146                  * returned.  This is a 'detached' RKM.  Must idle in this scenario,
147                  * since we might have migrated or otherwise weren't meant to PRKM
148                  * (can't return twice).  Also note that this may involve a core
149                  * migration, so we need to reread pcpui.*/
150                 cmb();
151                 pcpui = &per_cpu_info[core_id()];
152                 if (!in_early_rkmsg_ctx(pcpui))
153                         smp_idle();
154                 clear_rkmsg(pcpui);
155                 /* Some RKMs might turn on interrupts (perhaps in the future) and then
156                  * return. */
157                 disable_irq();
158         }
159 }
160
161 /* extremely dangerous and racy: prints out the immed and routine kmsgs for a
162  * specific core (so possibly remotely) */
163 void print_kmsgs(uint32_t coreid)
164 {
165         struct per_cpu_info *pcpui = &per_cpu_info[coreid];
166         void __print_kmsgs(struct kernel_msg_list *list, char *type)
167         {
168                 char *fn_name;
169                 struct kernel_message *kmsg_i;
170                 STAILQ_FOREACH(kmsg_i, list, link) {
171                         fn_name = get_fn_name((long)kmsg_i->pc);
172                         printk("%s KMSG on %d from %d to run %p(%s)\n", type,
173                                kmsg_i->dstid, kmsg_i->srcid, kmsg_i->pc, fn_name); 
174                         kfree(fn_name);
175                 }
176         }
177         __print_kmsgs(&pcpui->immed_amsgs, "Immedte");
178         __print_kmsgs(&pcpui->routine_amsgs, "Routine");
179 }
180
181 /* Debugging stuff */
182 void kmsg_queue_stat(void)
183 {
184         struct kernel_message *kmsg;
185         bool immed_emp, routine_emp;
186         for (int i = 0; i < num_cpus; i++) {
187                 spin_lock_irqsave(&per_cpu_info[i].immed_amsg_lock);
188                 immed_emp = STAILQ_EMPTY(&per_cpu_info[i].immed_amsgs);
189                 spin_unlock_irqsave(&per_cpu_info[i].immed_amsg_lock);
190                 spin_lock_irqsave(&per_cpu_info[i].routine_amsg_lock);
191                 routine_emp = STAILQ_EMPTY(&per_cpu_info[i].routine_amsgs);
192                 spin_unlock_irqsave(&per_cpu_info[i].routine_amsg_lock);
193                 printk("Core %d's immed_emp: %d, routine_emp %d\n", i, immed_emp,
194                routine_emp);
195                 if (!immed_emp) {
196                         kmsg = STAILQ_FIRST(&per_cpu_info[i].immed_amsgs);
197                         printk("Immed msg on core %d:\n", i);
198                         printk("\tsrc:  %d\n", kmsg->srcid);
199                         printk("\tdst:  %d\n", kmsg->dstid);
200                         printk("\tpc:   %p\n", kmsg->pc);
201                         printk("\targ0: %p\n", kmsg->arg0);
202                         printk("\targ1: %p\n", kmsg->arg1);
203                         printk("\targ2: %p\n", kmsg->arg2);
204                 }
205                 if (!routine_emp) {
206                         kmsg = STAILQ_FIRST(&per_cpu_info[i].routine_amsgs);
207                         printk("Routine msg on core %d:\n", i);
208                         printk("\tsrc:  %d\n", kmsg->srcid);
209                         printk("\tdst:  %d\n", kmsg->dstid);
210                         printk("\tpc:   %p\n", kmsg->pc);
211                         printk("\targ0: %p\n", kmsg->arg0);
212                         printk("\targ1: %p\n", kmsg->arg1);
213                         printk("\targ2: %p\n", kmsg->arg2);
214                 }
215                         
216         }
217 }
218
219 void print_kctx_depths(const char *str)
220 {
221         uint32_t coreid = core_id();
222         struct per_cpu_info *pcpui = &per_cpu_info[coreid];
223         
224         if (!str)
225                 str = "(none)";
226         printk("%s: Core %d, irq depth %d, ktrap depth %d, irqon %d\n", str, coreid,
227                irq_depth(pcpui), ktrap_depth(pcpui), irq_is_enabled());
228 }