9 #include <arch/console.h>
10 #include <arch/apic.h>
11 #include <ros/common.h>
24 /* Interrupt descriptor table. (Must be built at run time because
25 * shifted function addresses can't be represented in relocation records.)
27 // Aligned on an 8 byte boundary (SDM V3A 5-13)
28 gatedesc_t __attribute__ ((aligned (8))) (RO idt)[256] = { { 0 } };
29 pseudodesc_t RO idt_pd = {
30 sizeof(idt) - 1, (uint32_t) idt
33 /* global handler table, used by core0 (for now). allows the registration
34 * of functions to be called when servicing an interrupt. other cores
35 * can set up their own later.
38 #pragma cilnoremove("iht_lock")
41 handler_t TP(TV(t)) LCKD(&iht_lock) (RO interrupt_handlers)[NUM_INTERRUPT_HANDLERS];
43 static const char *NTS trapname(int trapno)
45 // zra: excnames is SREADONLY because Ivy doesn't trust const
46 static const char *NT const (RO excnames)[] = {
49 "Non-Maskable Interrupt",
52 "BOUND Range Exceeded",
54 "Device Not Available",
56 "Coprocessor Segment Overrun",
58 "Segment Not Present",
63 "x87 FPU Floating-Point Error",
66 "SIMD Floating-Point Exception"
69 if (trapno < sizeof(excnames)/sizeof(excnames[0]))
70 return excnames[trapno];
71 if (trapno == T_SYSCALL)
73 return "(unknown trap)";
80 extern segdesc_t (RO gdt)[];
82 // This table is made in trapentry.S by each macro in that file.
83 // It is layed out such that the ith entry is the ith's traphandler's
84 // (uint32_t) trap addr, then (uint32_t) trap number
85 struct trapinfo { uint32_t trapaddr; uint32_t trapnumber; };
86 extern struct trapinfo (BND(__this,trap_tbl_end) RO trap_tbl)[];
87 extern struct trapinfo (SNT RO trap_tbl_end)[];
88 int i, trap_tbl_size = trap_tbl_end - trap_tbl;
89 extern void ISR_default(void);
91 // set all to default, to catch everything
92 for(i = 0; i < 256; i++)
93 ROSETGATE(idt[i], 0, GD_KT, &ISR_default, 0);
95 // set all entries that have real trap handlers
96 // we need to stop short of the last one, since the last is the default
97 // handler with a fake interrupt number (500) that is out of bounds of
99 // if we set these to trap gates, be sure to handle the IRQs separately
100 // and we might need to break our pretty tables
101 for(i = 0; i < trap_tbl_size - 1; i++)
102 ROSETGATE(idt[trap_tbl[i].trapnumber], 0, GD_KT, trap_tbl[i].trapaddr, 0);
104 // turn on syscall handling and other user-accessible ints
105 // DPL 3 means this can be triggered by the int instruction
106 // STS_TG32 sets the IDT type to a Trap Gate (interrupts enabled)
107 idt[T_SYSCALL].gd_dpl = SINIT(3);
108 idt[T_SYSCALL].gd_type = SINIT(STS_TG32);
109 idt[T_BRKPT].gd_dpl = SINIT(3);
111 // Setup a TSS so that we get the right stack
112 // when we trap to the kernel.
113 ts.ts_esp0 = SINIT(KSTACKTOP);
114 ts.ts_ss0 = SINIT(GD_KD);
116 // Initialize the TSS field of the gdt.
117 SEG16ROINIT(gdt[GD_TSS >> 3],STS_T32A, (uint32_t)(&ts),sizeof(taskstate_t),0);
118 //gdt[GD_TSS >> 3] = (segdesc_t)SEG16(STS_T32A, (uint32_t) (&ts),
119 // sizeof(taskstate_t), 0);
120 gdt[GD_TSS >> 3].sd_s = SINIT(0);
126 asm volatile("lidt idt_pd");
128 // This will go away when we start using the IOAPIC properly
130 // set LINT0 to receive ExtINTs (KVM's default). At reset they are 0x1000.
131 write_mmreg32(LAPIC_LVT_LINT0, 0x700);
132 // mask it to shut it up for now
133 mask_lapic_lvt(LAPIC_LVT_LINT0);
139 print_regs(push_regs_t *regs)
141 cprintf(" edi 0x%08x\n", regs->reg_edi);
142 cprintf(" esi 0x%08x\n", regs->reg_esi);
143 cprintf(" ebp 0x%08x\n", regs->reg_ebp);
144 cprintf(" oesp 0x%08x\n", regs->reg_oesp);
145 cprintf(" ebx 0x%08x\n", regs->reg_ebx);
146 cprintf(" edx 0x%08x\n", regs->reg_edx);
147 cprintf(" ecx 0x%08x\n", regs->reg_ecx);
148 cprintf(" eax 0x%08x\n", regs->reg_eax);
152 print_trapframe(trapframe_t *tf)
154 static spinlock_t ptf_lock;
156 spin_lock_irqsave(&ptf_lock);
157 cprintf("TRAP frame at %p on core %d\n", tf, core_id());
158 print_regs(&tf->tf_regs);
159 cprintf(" gs 0x----%04x\n", tf->tf_gs);
160 cprintf(" fs 0x----%04x\n", tf->tf_fs);
161 cprintf(" es 0x----%04x\n", tf->tf_es);
162 cprintf(" ds 0x----%04x\n", tf->tf_ds);
163 cprintf(" trap 0x%08x %s\n", tf->tf_trapno, trapname(tf->tf_trapno));
164 cprintf(" err 0x%08x\n", tf->tf_err);
165 cprintf(" eip 0x%08x\n", tf->tf_eip);
166 cprintf(" cs 0x----%04x\n", tf->tf_cs);
167 cprintf(" flag 0x%08x\n", tf->tf_eflags);
168 cprintf(" esp 0x%08x\n", tf->tf_esp);
169 cprintf(" ss 0x----%04x\n", tf->tf_ss);
170 spin_unlock_irqsave(&ptf_lock);
174 trap_dispatch(trapframe_t *tf)
176 // Handle processor exceptions.
177 switch(tf->tf_trapno) {
182 page_fault_handler(tf);
185 // check for userspace, for now
186 assert(tf->tf_cs != GD_KT);
188 // syscall code wants an edible reference for current
189 proc_incref(current, 1);
190 tf->tf_regs.reg_eax =
191 syscall(current, tf->tf_regs.reg_eax, tf->tf_regs.reg_edx,
192 tf->tf_regs.reg_ecx, tf->tf_regs.reg_ebx,
193 tf->tf_regs.reg_edi, tf->tf_regs.reg_esi);
194 proc_decref(current, 1);
197 // Unexpected trap: The user process or the kernel has a bug.
199 if (tf->tf_cs == GD_KT)
200 panic("Damn Damn! Unhandled trap in the kernel!");
202 warn("Unexpected trap from userspace");
203 proc_incref(current, 1);
204 proc_destroy(current);
212 env_push_ancillary_state(env_t* e)
214 // TODO: (HSS) handle silly state (don't really want this per-process)
215 // Here's where you'll save FP/MMX/XMM regs
219 env_pop_ancillary_state(env_t* e)
221 // Here's where you'll restore FP/MMX/XMM regs
225 trap(trapframe_t *tf)
227 //printk("Incoming TRAP frame on core %d at %p\n", core_id(), tf);
229 /* Note we are not preemptively saving the TF in the env_tf. We do maintain
230 * a reference to it in current_tf (a per-cpu pointer).
231 * In general, only save the tf and any silly state once you know it
232 * is necessary (blocking). And only save it in env_tf when you know you
233 * are single core (PROC_RUNNING_S) */
236 if ((tf->tf_cs & ~3) != GD_UT && (tf->tf_cs & ~3) != GD_KT) {
238 panic("Trapframe with invalid CS!");
241 // Dispatch based on what type of trap occurred
244 // Return to the current process, which should be runnable.
245 proc_startcore(current, tf); // Note the comment in syscall.c
249 irq_handler(trapframe_t *tf)
251 // save a per-core reference to the tf
254 // cprintf("Incoming IRQ, ISR: %d on core %d\n", tf->tf_trapno, core_id());
255 // merge this with alltraps? other than the EOI... or do the same in all traps
257 extern handler_wrapper_t (RO handler_wrappers)[NUM_HANDLER_WRAPPERS];
259 // determine the interrupt handler table to use. for now, pick the global
260 handler_t TP(TV(t)) LCKD(&iht_lock) * handler_tbl = interrupt_handlers;
262 if (handler_tbl[tf->tf_trapno].isr != 0)
263 handler_tbl[tf->tf_trapno].isr(tf, handler_tbl[tf->tf_trapno].data);
264 // if we're a general purpose IPI function call, down the cpu_list
265 if ((I_SMP_CALL0 <= tf->tf_trapno) && (tf->tf_trapno <= I_SMP_CALL_LAST))
266 down_checklist(handler_wrappers[tf->tf_trapno & 0x0f].cpu_list);
268 // Send EOI. might want to do this in assembly, and possibly earlier
269 // This is set up to work with an old PIC for now
270 // Convention is that all IRQs between 32 and 47 are for the PIC.
271 // All others are LAPIC (timer, IPIs, perf, non-ExtINT LINTS, etc)
272 // For now, only 235-255 are available
273 assert(tf->tf_trapno >= 32); // slows us down, but we should never have this
278 //Old PIC relatd code. Should be gone for good, but leaving it just incase.
279 if (tf->tf_trapno < 48)
280 pic_send_eoi(tf->tf_trapno - PIC1_OFFSET);
288 register_interrupt_handler(handler_t TP(TV(t)) table[],
289 uint8_t int_num, poly_isr_t handler, TV(t) data)
291 table[int_num].isr = handler;
292 table[int_num].data = data;
296 page_fault_handler(trapframe_t *tf)
300 // Read processor's CR2 register to find the faulting address
303 // Handle kernel-mode page faults.
305 // TODO - one day, we'll want to handle this.
306 if ((tf->tf_cs & 3) == 0) {
308 panic("Page Fault in the Kernel at 0x%08x!", fault_va);
311 // We've already handled kernel-mode exceptions, so if we get here,
312 // the page fault happened in user mode.
314 // Call the environment's page fault upcall, if one exists. Set up a
315 // page fault stack frame on the user exception stack (below
316 // UXSTACKTOP), then branch to current->env_pgfault_upcall.
318 // The page fault upcall might cause another page fault, in which case
319 // we branch to the page fault upcall recursively, pushing another
320 // page fault stack frame on top of the user exception stack.
322 // The trap handler needs one word of scratch space at the top of the
323 // trap-time stack in order to return. In the non-recursive case, we
324 // don't have to worry about this because the top of the regular user
325 // stack is free. In the recursive case, this means we have to leave
326 // an extra word between the current top of the exception stack and
327 // the new stack frame because the exception stack _is_ the trap-time
330 // If there's no page fault upcall, the environment didn't allocate a
331 // page for its exception stack, or the exception stack overflows,
332 // then destroy the environment that caused the fault.
335 // user_mem_assert() and env_run() are useful here.
336 // To change what the user environment runs, modify 'current->env_tf'
337 // (the 'tf' variable points at 'current->env_tf').
339 // LAB 4: Your code here.
341 // Destroy the environment that caused the fault.
342 cprintf("[%08x] user fault va %08x ip %08x from core %d\n",
343 current->pid, fault_va, tf->tf_eip, core_id());
345 proc_incref(current, 1);
346 proc_destroy(current);
349 void sysenter_init(void)
351 write_msr(MSR_IA32_SYSENTER_CS, GD_KT);
352 write_msr(MSR_IA32_SYSENTER_ESP, ts.ts_esp0);
353 write_msr(MSR_IA32_SYSENTER_EIP, (uint32_t) &sysenter_handler);
356 /* This is called from sysenter's asm, with the tf on the kernel stack. */
357 void sysenter_callwrapper(struct Trapframe *tf)
359 // save a per-core reference to the tf
362 // syscall code wants an edible reference for current
363 proc_incref(current, 1);
364 tf->tf_regs.reg_eax = (intreg_t) syscall(current,
371 proc_decref(current, 1);
373 * careful here - we need to make sure that this current is the right
374 * process, which could be weird if the syscall blocked. it would need to
375 * restore the proper value in current before returning to here.
376 * likewise, tf could be pointing to random gibberish.
378 proc_startcore(current, tf);
381 struct kmem_cache *active_msg_cache;
382 void active_msg_init(void)
384 active_msg_cache = kmem_cache_create("active_msgs",
385 sizeof(struct active_message), HW_CACHE_ALIGN, 0, 0, 0);
388 uint32_t send_active_message(uint32_t dst, amr_t pc,
389 TV(a0t) arg0, TV(a1t) arg1, TV(a2t) arg2)
391 active_message_t *a_msg;
393 // note this will be freed on the destination core
394 a_msg = (active_message_t *CT(1))TC(kmem_cache_alloc(active_msg_cache, 0));
395 a_msg->srcid = core_id();
400 spin_lock_irqsave(&per_cpu_info[dst].amsg_lock);
401 STAILQ_INSERT_TAIL(&per_cpu_info[dst].active_msgs, a_msg, link);
402 spin_unlock_irqsave(&per_cpu_info[dst].amsg_lock);
403 // since we touched memory the other core will touch (the lock), we don't
405 send_ipi(get_hw_coreid(dst), I_ACTIVE_MSG);
409 /* Active message handler. We don't want to block other AMs from coming in, so
410 * we'll copy out the message and let go of the lock. This won't return until
411 * all pending AMs are executed. If the PC is 0, then this was an extra IPI and
412 * we already handled the message (or someone is sending IPIs without loading
413 * the active message...)
414 * Note that all of this happens from interrupt context, and interrupts are
415 * currently disabled for this gate. Interrupts need to be disabled so that the
416 * self-ipi doesn't preempt the execution of this active message. */
417 void __active_message(trapframe_t *tf)
419 per_cpu_info_t RO*myinfo = &per_cpu_info[core_id()];
420 active_message_t my_msg, *a_msg;
423 while (1) { // will break out when there are no more messages
424 /* Get the message */
425 spin_lock_irqsave(&myinfo->amsg_lock);
426 a_msg = STAILQ_FIRST(&myinfo->active_msgs);
427 /* No messages to execute, so break out, etc. */
429 spin_unlock_irqsave(&myinfo->amsg_lock);
432 STAILQ_REMOVE_HEAD(&myinfo->active_msgs, link);
433 spin_unlock_irqsave(&myinfo->amsg_lock);
434 // copy in, and then free, in case we don't return
436 kmem_cache_free(active_msg_cache, (void *CT(1))TC(a_msg));
438 /* In case the function doesn't return (which is common: __startcore,
439 * __death, etc), there is a chance we could lose an amsg. We can only
440 * have up to two interrupts outstanding, and if we never return, we
441 * never deal with any other amsgs. This extra IPI hurts performance
442 * but is only necessary if there is another outstanding message in the
443 * buffer, but makes sure we never miss out on an amsg. */
444 spin_lock_irqsave(&myinfo->amsg_lock);
445 if (!STAILQ_EMPTY(&myinfo->active_msgs))
446 send_self_ipi(I_ACTIVE_MSG);
447 spin_unlock_irqsave(&myinfo->amsg_lock);
448 /* Execute the active message */
449 my_msg.pc(tf, my_msg.srcid, my_msg.arg0, my_msg.arg1, my_msg.arg2);