From 5f8b9f7ff4a684692fd8e98c567ced34b5ba978f Mon Sep 17 00:00:00 2001 From: Geoffrey Challen Date: Thu, 9 Feb 2017 09:47:06 -0500 Subject: [PATCH] Low-level stack frame changes. --- kern/arch/mips/include/trapframe.h | 2 - kern/arch/mips/locore/exception-mips1.S | 111 +++++++++++++----------- kern/arch/mips/locore/trap.c | 4 +- kern/arch/mips/thread/cpu.c | 8 ++ kern/arch/sys161/dev/lamebus_machdep.c | 10 +++ 5 files changed, 81 insertions(+), 54 deletions(-) diff --git a/kern/arch/mips/include/trapframe.h b/kern/arch/mips/include/trapframe.h index 19d08bb..931ed89 100644 --- a/kern/arch/mips/include/trapframe.h +++ b/kern/arch/mips/include/trapframe.h @@ -69,8 +69,6 @@ struct trapframe { uint32_t tf_s7; uint32_t tf_t8; uint32_t tf_t9; - uint32_t tf_k0; /* dummy (see exception-mips1.S comments) */ - uint32_t tf_k1; /* dummy */ uint32_t tf_gp; uint32_t tf_sp; uint32_t tf_s8; diff --git a/kern/arch/mips/locore/exception-mips1.S b/kern/arch/mips/locore/exception-mips1.S index ad99c2a..f0fec13 100644 --- a/kern/arch/mips/locore/exception-mips1.S +++ b/kern/arch/mips/locore/exception-mips1.S @@ -101,6 +101,8 @@ mips_general_end: .text .type common_exception,@function .ent common_exception + .cfi_startproc + .cfi_signal_frame common_exception: mfc0 k0, c0_status /* Get status register */ andi k0, k0, CST_KUp /* Check the we-were-in-user-mode bit */ @@ -130,11 +132,12 @@ common_exception: */ /* - * Allocate stack space for 37 words to hold the trap frame, + * Allocate stack space for 35 words to hold the trap frame, * plus four more words for a minimal argument block, plus * one more for proper (64-bit) stack alignment. */ - addi sp, sp, -168 + addi sp, sp, -160 + .cfi_def_cfa sp, 0 /* * Save general registers. @@ -143,70 +146,89 @@ common_exception: * * The order here must match mips/include/trapframe.h. * - * gdb disassembles this code to try to figure out what registers - * are where, and it isn't very bright. So in order to make gdb be - * able to trace the stack back through here, we play some silly - * games. + * gdb uses the .cfi_offset assembler directives inserted below to + * to figure out where each register is stored. Since we've marked + * this function as a "signal handler" with the .cfi_signal_frame + * directive, gdb won't complain about the fact that the stack + * is noncontiguous (if we're coming from userland). * - * In particular: - * (1) We store the return address register into the epc slot, - * which makes gdb think it's the return address slot. Then - * we store the real epc value over that. - * (2) We store the current sp into the sp slot, which makes gdb - * think it's the stack pointer slot. Then we store the real - * value. - * (3) gdb also assumes that saved registers in a function are - * saved in order. This is why we put epc where it is, and - * handle the real value of ra afterwards. - * (4) Because gdb will think we're saving k0 and k1, we need to - * leave slots for them in the trap frame, even though the - * stuff we save there is useless. + * We also play a trick with the return address: we mark the ra + * register as stored to the stack normally and then mark the + * return address for *this* function as being in the k1 register + * using the .cfi_return_column directive. gdb is then able to + * recognize that the ra we've stored here is the return address + * for the function that was executing when this exception was + * taken. * - * This logic has not been tested against a recent gdb and has - * probably bitrotted. Someone(TM) should figure out what gdb - * currently expects -- or maybe even patch gdb to understand a - * better form of this that doesn't waste so many cycles. + * All of the cfi (call frame information) material is compiled + * into the .eh_frame section of the compiled kernel. */ - sw ra, 160(sp) /* dummy for gdb */ - sw s8, 156(sp) /* save s8 */ - sw sp, 152(sp) /* dummy for gdb */ - sw gp, 148(sp) /* save gp */ - sw k1, 144(sp) /* dummy for gdb */ - sw k0, 140(sp) /* dummy for gdb */ - - sw k1, 152(sp) /* real saved sp */ + sw s8, 148(sp) /* save s8 */ + .cfi_offset s8, 148 + sw k1, 144(sp) /* real saved sp */ + .cfi_offset sp, 144 + sw gp, 140(sp) /* save gp */ nop /* delay slot for store */ + .cfi_offset gp, 140 + .cfi_return_column k1 mfc0 k1, c0_epc /* Copr.0 reg 13 == PC for exception */ - sw k1, 160(sp) /* real saved PC */ + sw k1, 152(sp) /* real saved PC */ + .cfi_offset k1, 152 sw t9, 136(sp) + .cfi_offset t9, 136 sw t8, 132(sp) + .cfi_offset t8, 132 sw s7, 128(sp) + .cfi_offset s7, 128 sw s6, 124(sp) + .cfi_offset s6, 124 sw s5, 120(sp) + .cfi_offset s5, 120 sw s4, 116(sp) + .cfi_offset s4, 116 sw s3, 112(sp) + .cfi_offset s3, 112 sw s2, 108(sp) + .cfi_offset s2, 108 sw s1, 104(sp) + .cfi_offset s1, 104 sw s0, 100(sp) + .cfi_offset s0, 100 sw t7, 96(sp) + .cfi_offset t7, 96 sw t6, 92(sp) + .cfi_offset t6, 92 sw t5, 88(sp) + .cfi_offset t5, 88 sw t4, 84(sp) + .cfi_offset t4, 84 sw t3, 80(sp) + .cfi_offset t3, 80 sw t2, 76(sp) + .cfi_offset t2, 76 sw t1, 72(sp) + .cfi_offset t1, 72 sw t0, 68(sp) + .cfi_offset t0, 68 sw a3, 64(sp) + .cfi_offset a3, 64 sw a2, 60(sp) + .cfi_offset a2, 60 sw a1, 56(sp) + .cfi_offset a1, 56 sw a0, 52(sp) + .cfi_offset a0, 52 sw v1, 48(sp) + .cfi_offset v1, 48 sw v0, 44(sp) + .cfi_offset v0, 44 sw AT, 40(sp) + .cfi_offset AT, 40 sw ra, 36(sp) + .cfi_offset ra, 36 /* * Save special registers. @@ -227,11 +249,6 @@ common_exception: mfc0 t4, c0_cause sw t4, 24(sp) /* Copr.0 reg 13 == exception cause */ - /* - * Pretend to save $0 for gdb's benefit. - */ - sw $0, 12(sp) - /* * Load the curthread register if coming from user mode. */ @@ -260,9 +277,6 @@ common_exception: jal mips_trap /* call it */ nop /* delay slot */ - /* Something must be here or gdb doesn't find the stack frame. */ - nop - /* * Now restore stuff and return from the exception. * Interrupts should be off. @@ -309,20 +323,17 @@ exception_return: lw s7, 128(sp) lw t8, 132(sp) lw t9, 136(sp) + lw gp, 140(sp) /* restore gp */ + /* 144(sp) stack pointer - below */ + lw s8, 148(sp) /* restore s8 */ + lw k1, 152(sp) /* fetch exception return PC into k1 */ - /* 140(sp) "saved" k0 was dummy garbage anyway */ - /* 144(sp) "saved" k1 was dummy garbage anyway */ - - lw gp, 148(sp) /* restore gp */ - /* 152(sp) stack pointer - below */ - lw s8, 156(sp) /* restore s8 */ - lw k0, 160(sp) /* fetch exception return PC into k0 */ - - lw sp, 152(sp) /* fetch saved sp (must be last) */ + lw sp, 144(sp) /* fetch saved sp (must be last) */ /* done */ - jr k0 /* jump back */ + jr k1 /* jump back */ rfe /* in delay slot */ + .cfi_endproc .end common_exception /* diff --git a/kern/arch/mips/locore/trap.c b/kern/arch/mips/locore/trap.c index d3873eb..69ae12c 100644 --- a/kern/arch/mips/locore/trap.c +++ b/kern/arch/mips/locore/trap.c @@ -130,8 +130,8 @@ mips_trap(struct trapframe *tf) bool iskern; int spl; - /* The trap frame is supposed to be 37 registers long. */ - KASSERT(sizeof(struct trapframe)==(37*4)); + /* The trap frame is supposed to be 35 registers long. */ + KASSERT(sizeof(struct trapframe)==(35*4)); /* * Extract the exception code info from the register fields. diff --git a/kern/arch/mips/thread/cpu.c b/kern/arch/mips/thread/cpu.c index 5acce5b..d43a4ec 100644 --- a/kern/arch/mips/thread/cpu.c +++ b/kern/arch/mips/thread/cpu.c @@ -54,6 +54,14 @@ * * These arrays are also used to start up new CPUs, for roughly the * same reasons. + * + * The values in the current cpu's slots in these arrays are updated + * with the current thread's information in trap.c before heading to + * userlevel, as well as being initialized in cpu_machdep_init below. + * This means that (unless something really horrible happens) on entry + * to the kernel, and when a new CPU starts up in cpu_start_secondary, + * they will have the information needed to figure out who we are and + * proceed. */ vaddr_t cpustacks[MAXCPUS]; diff --git a/kern/arch/sys161/dev/lamebus_machdep.c b/kern/arch/sys161/dev/lamebus_machdep.c index c6c62ce..0cc1fb2 100644 --- a/kern/arch/sys161/dev/lamebus_machdep.c +++ b/kern/arch/sys161/dev/lamebus_machdep.c @@ -42,6 +42,7 @@ #include #include #include +#include #include "autoconf.h" /* @@ -275,6 +276,15 @@ mainbus_send_ipi(struct cpu *target) lamebus_assert_ipi(lamebus, target); } +/* + * Trigger the debugger. + */ +void +mainbus_debugger(void) +{ + ltrace_stop(0); +} + /* * Interrupt dispatcher. */