Date: Thu, 18 Jan 2001 07:02:56 +0100 From: Tor.Egge@fast.no To: sos@freebsd.dk Cc: jasone@canonware.com, current@FreeBSD.ORG Subject: Re: Debugging SMP instability (was Re: HEADS-UP: await/asleep removal imminent) Message-ID: <200101180602.HAA11429@midten.fast.no> In-Reply-To: Your message of "Wed, 17 Jan 2001 20:35:24 %2B0100 (CET)" References: <200101171935.UAA25627@freebsd.dk>
next in thread | previous in thread | raw e-mail | index | archive | help
----Next_Part(Thu_Jan_18_07:01:01_2001)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit > Again I'll offer to run any and all code or patches to -current you > guys can come up with, but I simply dont have the time to sit down > and analyze into details what you have been doing... The enclosed patch implements a virtual NMI pushbutton by programming the IOAPIC to deliver an NMI when sio1 generates an interrupt. DDB should be defined in the kernel config file. getty should not run on ttyd1 when this patch is applied. A serial console on sio0 is recommended. If you still cannot break into the kernel debugger when the machine locks up then a rogue device is probably blocking the system (or the debugger is trying to obtain a mutex held by somebody else) - Tor Egge ----Next_Part(Thu_Jan_18_07:01:01_2001)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit Index: sys/i386/i386/mpapic.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/mpapic.c,v retrieving revision 1.45 diff -u -r1.45 mpapic.c --- sys/i386/i386/mpapic.c 2001/01/10 04:43:46 1.45 +++ sys/i386/i386/mpapic.c 2001/01/18 05:44:30 @@ -269,6 +269,41 @@ /* return GOOD status */ return 0; } + + +void +enable_sio_NMI(int irq) +{ + u_char select; /* the select register is 8 bits */ + u_int32_t flags; /* the window register is 32 bits */ + u_int32_t target; /* the window register is 32 bits */ + u_int32_t vector; /* the window register is 32 bits */ + int apic; + int pin; + + if (irq < 0 || irq > 15) { + printf("Could not enable NMI for irq %d\n", irq); + return; + } + apic = int_to_apicintpin[irq].ioapic; + pin = int_to_apicintpin[irq].int_pin; + + target = CPU_TO_ID(0) << 24; + select = IOAPIC_REDTBL0 + (2 * pin); + vector = TPR_FAST_INTS + irq; + flags = ((u_int32_t) + (IOART_INTMCLR | + IOART_TRGREDG | + IOART_INTAHI | + IOART_DESTPHY | + IOART_DELNMI)); + + io_apic_write(apic, select, flags | vector); + io_apic_write(apic, select + 1, target); + printf("Enabled NMI for irq %d\n", irq); + printf("XXX IOAPIC #%d intpin %d ->irq %d vector 0x%x (Delivery mode NMI)\n", + apic, pin, irq, vector); +} #undef DEFAULT_ISA_FLAGS #undef DEFAULT_FLAGS Index: sys/i386/i386/trap.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/trap.c,v retrieving revision 1.164 diff -u -r1.164 trap.c --- sys/i386/i386/trap.c 2001/01/10 04:43:46 1.164 +++ sys/i386/i386/trap.c 2001/01/18 05:44:30 @@ -248,7 +248,8 @@ atomic_add_int(&cnt.v_trap, 1); - if ((frame.tf_eflags & PSL_I) == 0) { + if ((frame.tf_eflags & PSL_I) == 0 && + frame.tf_trapno != T_NMI) { /* * Buggy application or kernel code has disabled * interrupts and then trapped. Enabling interrupts @@ -285,8 +286,38 @@ enable_intr(); } - mtx_enter(&Giant, MTX_DEF); + if (frame.tf_trapno == T_NMI) { + /* If we can't get Giant then forward NMI to next CPU */ + if (mtx_try_enter(&Giant, MTX_DEF) == 0) { + u_long icr_lo; + u_long icr_hi; + int target; + + target = PCPU_GET(cpuid) + 1; + if (((1 << target) & PCPU_GET(other_cpus)) == 0) + target = 0; + + /* write the destination field for the target AP */ + icr_hi = (lapic.icr_hi & ~APIC_ID_MASK) | + (cpu_num_to_apic_id[target] << 24); + lapic.icr_hi = icr_hi; + + /* write command */ + icr_lo = (lapic.icr_lo & APIC_RESV2_MASK) | + APIC_DEST_DESTFLD | APIC_DELMODE_NMI | 0xff; + lapic.icr_lo = icr_lo; + + /* wait for pending status end */ + while (lapic.icr_lo & APIC_DELSTAT_MASK) + /* spin */ ; + __asm __volatile("int $0xff"); + + return; + } + } else + mtx_enter(&Giant, MTX_DEF); + #if defined(I586_CPU) && !defined(NO_F00F_HACK) restart: #endif @@ -388,6 +419,9 @@ */ if (ddb_on_nmi) { printf ("NMI ... going to debugger\n"); + sioEATintr(); + __asm __volatile("int $0xff"); + enable_intr(); kdb_trap (type, 0, &frame); } #endif /* DDB */ @@ -617,6 +651,9 @@ */ if (ddb_on_nmi) { printf ("NMI ... going to debugger\n"); + sioEATintr(); + __asm __volatile("int $0xff"); + enable_intr(); kdb_trap (type, 0, &frame); } #endif /* DDB */ Index: sys/isa/sio.c =================================================================== RCS file: /home/ncvs/src/sys/isa/sio.c,v retrieving revision 1.321 diff -u -r1.321 sio.c --- sys/isa/sio.c 2000/12/26 06:52:57 1.321 +++ sys/isa/sio.c 2001/01/18 05:44:30 @@ -439,6 +439,17 @@ { -1, -1 } }; +#define DDB_BREAK_MASK (IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC) +#define DDB_NMI + +#ifdef TRIPLE_BREAK_TO_DEBUGGER +#ifndef TRIPLE_BREAK_TIMEOUT +#define TRIPLE_BREAK_TIMEOUT 10 +#endif +int triple_break_count; /* number of breaks detected */ +int triple_break_time; /* time_second sampled at first break */ +#endif + #ifdef COM_ESP /* XXX configure this properly. */ static Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, }; @@ -1179,6 +1190,33 @@ com->lt_out.c_ispeed = com->lt_out.c_ospeed = com->lt_in.c_ispeed = com->lt_in.c_ospeed = com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate; +#if defined(DDB) && defined(BREAK_TO_DEBUGGER) && defined(DDB_BREAK_MASK) + outb(iobase + com_ier, DDB_BREAK_MASK); +#endif +#if defined(DDB) && defined(DDB_BREAK_MASK) && defined(DDB_NMI) + } else if (unit == 1) { + com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED; + com->it_in.c_iflag = TTYDEF_IFLAG; + com->it_in.c_oflag = TTYDEF_OFLAG; + com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL; + com->it_in.c_lflag = TTYDEF_LFLAG; + com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL; + com->lt_out.c_ispeed = com->lt_out.c_ospeed = + com->lt_in.c_ispeed = com->lt_in.c_ospeed = + com->it_in.c_ispeed = com->it_in.c_ospeed = + comdefaultrate; + (void) inb(com->line_status_port); + (void) inb(com->data_port); + com->prev_modem_status = com->last_modem_status + = inb(com->modem_status_port); + if (COM_IIR_TXRDYBUG(com->flags)) { + outb(com->intr_ctl_port, IER_ERXRDY | IER_ERLS + | IER_EMSC); + } else { + outb(com->intr_ctl_port, IER_ERXRDY | IER_ETXRDY + | IER_ERLS | IER_EMSC); + } +#endif } else com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED; if (siosetwater(com, com->it_in.c_ispeed) != 0) { @@ -1355,10 +1393,56 @@ if (ret) device_printf(dev, "could not activate interrupt\n"); } +#if defined(DDB) && defined(DDB_BREAK_MASK) && defined(DDB_NMI) && defined(APIC_IO) + if (unit == 1) { + u_long xirq; + if (bus_get_resource(dev, SYS_RES_IRQ, 0, &xirq, NULL) == 0) { + printf("XXX: sio1 irq is %lu\n", xirq); + enable_sio_NMI(xirq); + } + } +#endif return (0); } + +void +sioEATintr(void) +{ + struct com_s *com; + u_char line_status; + u_char modem_status; + u_char recv_data; + u_char int_ctl; + u_char int_id; + + com = com_addr(1); + if (com == NULL) + return; + + int_id = inb(com->int_id_port); + int_ctl = inb(com->intr_ctl_port); + while (1) { + line_status = inb(com->line_status_port); + while (line_status & LSR_RCV_MASK) { + if ((line_status & LSR_RXRDY) == 0) + recv_data = 0; + else + recv_data = inb(com->data_port); + if ((line_status & + (LSR_BI | LSR_FE | LSR_PE)) != 0) { + } + line_status = inb(com->line_status_port); + } + modem_status = inb(com->modem_status_port); + int_id = inb(com->int_id_port); + if ((int_id & IIR_IMASK) == IIR_NOPEND) + break; + } +} + + static int sioopen(dev, flag, mode, p) dev_t dev; @@ -1596,7 +1680,12 @@ com->pps.ppsparam.mode = 0; sio_setreg(com, com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); { - sio_setreg(com, com_ier, 0); +#if defined(DDB) && defined(BREAK_TO_DEBUGGER) && defined(DDB_BREAK_MASK) + if (com->unit == comconsole) + sio_setreg(com, com_ier, DDB_BREAK_MASK); + else +#endif + sio_setreg(com, com_ier, 0); tp = com->tp; if (tp->t_cflag & HUPCL /* @@ -1946,7 +2035,27 @@ if (line_status & LSR_BI) { #if defined(DDB) && defined(BREAK_TO_DEBUGGER) if (com->unit == comconsole) { +#ifdef TRIPLE_BREAK_TO_DEBUGGER + if (time_second > + triple_break_time + + TRIPLE_BREAK_TIMEOUT) + triple_break_count = 0; + triple_break_count++; + if (triple_break_count == 1) + triple_break_time = + time_second; + else if (triple_break_count + == 3) { + triple_break_count = 0; + mtx_exit(&sio_lock, MTX_SPIN); + breakpoint(); + mtx_enter(&sio_lock, MTX_SPIN); + } +#else + mtx_exit(&sio_lock, MTX_SPIN); breakpoint(); + mtx_enter(&sio_lock, MTX_SPIN); +#endif goto cont; } #endif ----Next_Part(Thu_Jan_18_07:01:01_2001)---- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200101180602.HAA11429>