I can restore callstack using T32 as followings;

[<c001df40>] do_page_fault+0x338/0x3f8 

[<c0008544>] do_DataAbort+0x38/0x98 

[<c0015058>] __dabt_svc+0x38/0x60 

[<c031a5a0>] tty_wakeup+0xc/0x64 

[<c06f82ec>] gs_start_io+0x94/0xf4 

[<c06f8698>] gserial_connect+0xe0/0x180

[<c06f7578>] acm_set_alt+0x88/0x1a8 

[<c06f3c5c>] composite_setup+0xd34/0x1520 

[<c070d154>] android_setup+0x1f4/0x1fc 

[<c03fc6e8>] forward_to_driver+0x64/0x100 

[<c03fd418>] musb_g_ep0_irq+0x7d8/0x1c18 

[<c03fb094>] musb_interrupt+0x94/0xc78 

[<c04024f0>] generic_interrupt+0xc34/0x1218 

[<c009b020>] handle_irq_event_percpu+0xe0/0x2e4

[<c009b268>] handle_irq_event+0x44/0x64

[<c009df54>] handle_fasteoi_irq+0xe8/0x1a4 

[<c009a7dc>] __handle_domain_irq+0x104/0x264 

[<c0008668>] gic_handle_irq+0x2c/0x64 

[<c00153a8>] __irq_usr+0x48/0x60


Kernel panic occurs because R0 is holding 0x0 whose instance is (struct tty_struct *tty).

NSR:C031A594|E1A0C00D tty_wakeup: cpy r12,r13

NSR:C031A598|E92DD830 push {r4-r5,r11-r12,r14,pc}

NSR:C031A59C|E24CB004 sub r11,r12,#0x4 ; r11,r12,#4

NSR:C031A5A0|E59031CC_______________ldr____r3,r0,#0x1CC  //<--


Let me take times to look into tty_wakeup() more.

void tty_wakeup(struct tty_struct *tty)

{

    struct tty_ldisc *ld;


    if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) { // <<-- kernel panic

        ld = tty_ldisc_ref(tty);


        if (ld)

        {

           if (ld->ops->write_wakeup) ld->ops->write_wakeup(tty);

           tty_ldisc_deref(ld);

        }

    }


    wake_up_interruptible_poll(&tty->write_wait, POLLOUT);

}


As kernel log indicates below right before kernel panic occurs, gs_close() is called as mdl_sock_host.

Inside gs_close(), port->port.tty is updated as NULL.

[ 6285.082083 / 06-01 11:43:40.318] -(4)[981:mdl_sock_host]gs_close: ttyGS1 (d3681900,d7e1ca80) ...


<< Code fragment >> 

static void gs_close(struct tty_struct *tty, struct file *file)

{

    struct gs_port *port = tty->driver_data;

    struct gserial *gser;


//snip

    if (gser == NULL)

        gs_buf_free(&port->port_write_buf);

    else

        gs_buf_clear(&port->port_write_buf);

        tty->driver_data = NULL;


        port->port.tty = NULL; // <<--

        port->openclose = false;


Right after gs_close() is called, acm driver calls tty_wakeup() function during enumeration operation, which causes kernel panic.


With following patch, kernel crash was fixed. 

diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c

index 27a7cdc..4b88415 100644

? a/drivers/usb/gadget/u_serial.c

+++ b/drivers/usb/gadget/u_serial.c

@@ -784,8 +784,11 @@ static int gs_start_io(struct gs_port *port)

    port->n_read = 0;

    started = gs_start_rx(port);


+   if (!port->port_usb)

+      return -EIO;

+

/* unblock any pending writes into our circular buffer */


    if (started) {

+        if (started && port->port.tty) {

                tty_wakeup(port->port.tty);

         } else {

           gs_free_requests(ep, head, &port->read_allocated);


The call to tty_wakeup() is only made in case port->port.tty points to valid address.

+ Recent posts