Friday, October 14, 2011

FIQ debugger, redux.

I found myself (temporarily, thanks Chris!) in the posession of an OLPC XO 1.75 . Very interesting hardware. The Marvell chip isn't something to particularly rave about (compared to the Xoom's dual Cortex-A9s), but at the end of the day it's a completely open platform (hardware and software), that runs an OS based on Fedora. Plus it uses OpenFirmware instead of some half-baked ROM monitor or a UEFI.. Totally cool. The other great thing is that the kernel is a 3.0-based kernel (not mainline, but w/e), which makes this that much more interesting, especially in light of my interests in MMC flash block core and ARM KGDB/KDB support.

Anyway, while playing with it I had the system wedge up in some totally useless state. Given a lack of a FIQ watchdog or debugger code, I decided to port the FIQ debugger over...

Update: Looks like the XO folks found it useful to hunt for some bugs, cool!


The end result - https://github.com/andreiw/andreiw-wip/tree/master/linux/olpc/fiq. Should apply cleanly to the stuff over at http://wiki.laptop.org/go/Kernel.

The overall tasks were:
  • Enable FIQ support for the MMP2 platform, i.e. add an OOB interface for enabling/disabling FIQ triggering on a particular INT# line.
  • Bring over Google's FIQ glue, which lets you write FIQ handlers in a normal C environment (and deals with suspend/resume and MP support). Not sure I understand why this stuff isn't in mainline yet - I presume because nothing uses it. It certainly has no dependency on Android.
  • Implement the FIQ debugger platform device for MMP2. This is the platform-specific driver which is used the FIQ debugger core, and provides UART access, FIQ INT# manipulation, and the ability to force an IRQ. The later is crucial, since the UART is managed entirely by the FIQ handler, and getting stuff to happen in normal "kernel context" needs code to run in at least IRQ level, so you need to be able to trigger a hardware IRQ.
  • Turn on the FIQ debugger platform device for the XO 1.75 kernel, binding it to a specific UART.
  • Port Google's FIQ debugger into a non-Android environment, at the same time bringing it up to date (from K36 to K3.0) and improving the interface to the platform device.
  • Add my KGDB/KGDB FIQ patch on top.
 Some of the better functionality not seen elsewhere ;-):
  • Ability to override baud rate from boot parameter.
  • Ability to implement platform-specific commands.
  • Ability to specify OOB struct clk that is not associated with the pdev.
  • Of course, the ability to enter into KDB/KGDB mode.
Forcing a hardware IRQ posed an interesting problem. Many thanks to Mitch Bradley (*the* OpenFirmware guy), who suggested using the IPC block to trigger a particular IRQ. The mechanism pretty much triggers only that one IRQ, but that in itself is sufficient. The IPC block should really be exposed as a secondary interrupt controller, as it effectively implements more interrupt lines chained off that one IRQ, but the Marvell documentation for this is clearly not available for me. Ran into an issue where the IRQ would instantly fire as soon as I would enable it, but I guessed there were some extra lines in the IPC block which needed to be masked away, and looks like I was right.

Code for the IRQ force functionality:
#define IRQ_MMP2_IPC   56
...
static void debug_force_irq(struct platform_device *pdev,
 unsigned int irq)
{
 BUG_ON(irq != IRQ_MMP2_IPC);
 writel(0x400, APB_VIRT_BASE + 0x1d008);
}

static void debug_force_irq_ack(struct platform_device *pdev,
 unsigned int irq)
{
 BUG_ON(irq != IRQ_MMP2_IPC);
 writel(0x400, APB_VIRT_BASE + 0x1d40c);
}

int __init mmp2_fiq_debug_init(unsigned int base, struct clk *clk,
 int irq, int signal_irq, int wakeup_irq)
{
...
 /*
 * Hack - the IPC block should be exposed as a
 * secondary PIC, but we don't know enough about
 * it's registers to do that :(. The IPC block
 * has many secondary "interrupts" and these
 * need to be acked, or we are going to run into
 * a bajillion of INT #56 as soon as we enable it.
 */
 writel(0xffffffff, APB_VIRT_BASE + 0x1d40c);
...
}

To use the FIQ debugger with my patches on the XO 1.75:
  • Your .config should contain:
    CONFIG_MMP2_FIQ_DEBUGGER=y
    CONFIG_FIQ_DEBUGGER=y
    CONFIG_FIQ_DEBUGGER_CONSOLE=y
    CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE=y
    CONFIG_FIQ_DEBUGGER_KGDB_DEFAULT_ENABLE=y
    CONFIG_FIQ_DEBUGGER_KGDB_INSECURE=y
    CONFIG_FIQ_DEBUGGER_KGDB=y
    
  • Your boot parameters should have a console=ttyFIQ0, with the UART used corresponding to /dev/ttyS2.
  • Port is configured as 115200 8n1 by default. To change, pass mmp2_fiq_debugger.baud=9600 or desired baud rate.
  • If you send Ctrl-Break you should be greeted by:
    debug> 
    debug> help
    FIQ Debugger commands:
     pc            PC status
     regs          Register dump
     allregs       Extended Register dump
     bt            Stack trace
     kmesg         Dump dmesg
     reboot        Reboot
     irqs          Interupt status
     version       Kernel version
     sleep         Allow sleep while in FIQ
     nosleep       Disable sleep while in FIQ
     console       Switch terminal to console
     cpu           Current CPU
     cpu   Switch to CPU
     kgdb          Break into or return to KGDB
     kgdbon        Enable KGDB
     kgdboff       Disable KGDB
    debug>
    
  • If you're in KGDB/KDB mode, you need to Ctrl-Break twice to get back to FIQ mode.

Enjoy! :-)

No comments:

Post a Comment