Implement 9ns FD functions with fd tables
[akaros.git] / kern / src / trap.c
index 67266d6..cf28850 100644 (file)
 #include <kdebug.h>
 #include <kmalloc.h>
 
+static void print_unhandled_trap(struct proc *p, struct user_context *ctx,
+                                 unsigned int trap_nr, unsigned int err,
+                                 unsigned long aux)
+{
+       print_user_ctx(ctx);
+       printk("err 0x%x (for PFs: User 4, Wr 2, Rd 1), aux %p\n", err, aux);
+       debug_addr_proc(p, get_user_ctx_pc(ctx));
+       print_vmrs(p);
+       backtrace_user_ctx(p, ctx);
+}
+
+/* Traps that are considered normal operations. */
+static bool benign_trap(unsigned int err)
+{
+       return err & PF_VMR_BACKED;
+}
+
+static void printx_unhandled_trap(struct proc *p, struct user_context *ctx,
+                                  unsigned int trap_nr, unsigned int err,
+                                  unsigned long aux)
+{
+       if (printx_on && !benign_trap(err))
+               print_unhandled_trap(p, ctx, trap_nr, err, aux);
+}
+
+void reflect_unhandled_trap(unsigned int trap_nr, unsigned int err,
+                            unsigned long aux)
+{
+       uint32_t coreid = core_id();
+       struct per_cpu_info *pcpui = &per_cpu_info[coreid];
+       struct proc *p = pcpui->cur_proc;
+       uint32_t vcoreid = pcpui->owning_vcoreid;
+       struct preempt_data *vcpd = &p->procdata->vcore_preempt_data[vcoreid];
+       struct hw_trapframe *hw_tf = &pcpui->cur_ctx->tf.hw_tf;
+       assert(p);
+       assert(pcpui->cur_ctx && (pcpui->cur_ctx->type == ROS_HW_CTX));
+       if (!proc_is_vcctx_ready(p)) {
+               printk("Unhandled user trap from early SCP\n");
+               goto error_out;
+       }
+       if (vcpd->notif_disabled) {
+               printk("Unhandled user trap in vcore context\n");
+               goto error_out;
+       }
+       printx_unhandled_trap(p, pcpui->cur_ctx, trap_nr, err, aux);
+       /* need to store trap_nr, err code, and aux into the tf so that it can get
+        * extracted on the other end, and we need to flag the TF in some way so we
+        * can tell it was reflected.  for example, on a PF, we need some number (14
+        * on x86), the prot violation (write, read, etc), and the virt addr (aux).
+        * parlib will know how to extract this info. */
+       __arch_reflect_trap_hwtf(hw_tf, trap_nr, err, aux);
+       /* the guts of a __notify */
+       vcpd->notif_disabled = TRUE;
+       vcpd->uthread_ctx = *pcpui->cur_ctx;
+       memset(pcpui->cur_ctx, 0, sizeof(struct user_context));
+       proc_init_ctx(pcpui->cur_ctx, vcoreid, vcpd->vcore_entry,
+                     vcpd->vcore_stack, vcpd->vcore_tls_desc);
+       return;
+error_out:
+       print_unhandled_trap(p, pcpui->cur_ctx, trap_nr, err, aux);
+       enable_irq();
+       proc_destroy(p);
+}
+
+uintptr_t get_user_ctx_pc(struct user_context *ctx)
+{
+       switch (ctx->type) {
+               case ROS_HW_CTX:
+                       return get_hwtf_pc(&ctx->tf.hw_tf);
+               case ROS_SW_CTX:
+                       return get_swtf_pc(&ctx->tf.sw_tf);
+               default:
+                       warn("Bad context type %d for ctx %p\n", ctx->type, ctx);
+                       return 0;
+       }
+}
+
+uintptr_t get_user_ctx_fp(struct user_context *ctx)
+{
+       switch (ctx->type) {
+               case ROS_HW_CTX:
+                       return get_hwtf_fp(&ctx->tf.hw_tf);
+               case ROS_SW_CTX:
+                       return get_swtf_fp(&ctx->tf.sw_tf);
+               default:
+                       warn("Bad context type %d for ctx %p\n", ctx->type, ctx);
+                       return 0;
+       }
+}
+
 struct kmem_cache *kernel_msg_cache;
 
 void kernel_msg_init(void)
@@ -69,19 +159,25 @@ void handle_kmsg_ipi(struct hw_trapframe *hw_tf, void *data)
 {
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
        struct kernel_message *kmsg_i, *temp;
-       assert(!irq_is_enabled());
-       /* Avoid locking if the list appears empty (lockless peak is okay) */
+       /* Avoid locking if the list appears empty (lockless peek is okay) */
        if (STAILQ_EMPTY(&pcpui->immed_amsgs))
                return;
        /* The lock serves as a cmb to force a re-read of the head of the list */
-       spin_lock(&pcpui->immed_amsg_lock);
+       spin_lock_irqsave(&pcpui->immed_amsg_lock);
        STAILQ_FOREACH_SAFE(kmsg_i, &pcpui->immed_amsgs, link, temp) {
                pcpui_trace_kmsg(pcpui, (uintptr_t)kmsg_i->pc);
                kmsg_i->pc(kmsg_i->srcid, kmsg_i->arg0, kmsg_i->arg1, kmsg_i->arg2);
                STAILQ_REMOVE(&pcpui->immed_amsgs, kmsg_i, kernel_message, link);
                kmem_cache_free(kernel_msg_cache, (void*)kmsg_i);
        }
-       spin_unlock(&pcpui->immed_amsg_lock);
+       spin_unlock_irqsave(&pcpui->immed_amsg_lock);
+}
+
+bool has_routine_kmsg(void)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       /* lockless peek */
+       return !STAILQ_EMPTY(&pcpui->routine_amsgs);
 }
 
 /* Helper function, gets the next routine KMSG (RKM).  Returns 0 if the list was
@@ -89,10 +185,11 @@ void handle_kmsg_ipi(struct hw_trapframe *hw_tf, void *data)
 static kernel_message_t *get_next_rkmsg(struct per_cpu_info *pcpui)
 {
        struct kernel_message *kmsg;
-       /* Avoid locking if the list appears empty (lockless peak is okay) */
+       /* Avoid locking if the list appears empty (lockless peek is okay) */
        if (STAILQ_EMPTY(&pcpui->routine_amsgs))
                return 0;
-       /* The lock serves as a cmb to force a re-read of the head of the list */
+       /* The lock serves as a cmb to force a re-read of the head of the list.
+        * IRQs are disabled by our caller. */
        spin_lock(&pcpui->routine_amsg_lock);
        kmsg = STAILQ_FIRST(&pcpui->routine_amsgs);
        if (kmsg)
@@ -183,7 +280,7 @@ void kmsg_queue_stat(void)
 {
        struct kernel_message *kmsg;
        bool immed_emp, routine_emp;
-       for (int i = 0; i < num_cpus; i++) {
+       for (int i = 0; i < num_cores; i++) {
                spin_lock_irqsave(&per_cpu_info[i].immed_amsg_lock);
                immed_emp = STAILQ_EMPTY(&per_cpu_info[i].immed_amsgs);
                spin_unlock_irqsave(&per_cpu_info[i].immed_amsg_lock);
@@ -226,3 +323,13 @@ void print_kctx_depths(const char *str)
        printk("%s: Core %d, irq depth %d, ktrap depth %d, irqon %d\n", str, coreid,
               irq_depth(pcpui), ktrap_depth(pcpui), irq_is_enabled());
 }
+
+void print_user_ctx(struct user_context *ctx)
+{
+       if (ctx->type == ROS_SW_CTX)
+               print_swtrapframe(&ctx->tf.sw_tf);
+       else if (ctx->type == ROS_HW_CTX)
+               print_trapframe(&ctx->tf.hw_tf);
+       else
+               printk("Bad TF %p type %d!\n", ctx, ctx->type);
+}