Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:41

0001 /*
0002  * Copyright (c) 2016.
0003  * Chris Johns <chrisj@rtems.org>
0004  *
0005  * This software is Copyright (C) 1998 by T.sqware - all rights limited
0006  * It is provided in to the public domain "as is", can be freely modified
0007  * as far as this copyight notice is kept unchanged, but does not imply
0008  * an endorsement by T.sqware of the product in which it is included.
0009  */
0010 
0011 #include <bsp.h>
0012 #include <bsp/irq-generic.h>
0013 #include <libchip/serial.h>
0014 
0015 #include "../../../shared/dev/serial/legacy-console.h"
0016 
0017 int  putDebugChar(int ch);     /* write a single character      */
0018 int  getDebugChar(void);       /* read and return a single char */
0019 
0020 /* Check is any characters received are a ^C */
0021 int i386_gdb_uart_ctrl_c_check(void);
0022 
0023 /* Raw interrupt handler. */
0024 void i386_gdb_uart_isr(void);
0025 
0026 /* assign an exception handler */
0027 void exceptionHandler(int, void (*handler)(void));
0028 
0029 /* User supplied remote debug option. */
0030 extern int remote_debug;
0031 
0032 /* Current uart and port used by the gdb stub */
0033 static int          uart_current;
0034 static int          uart_vector;
0035 static console_tbl* port_current;
0036 
0037 /*
0038  * Interrupt service routine for all, it does it check whether ^C is received
0039  * if yes it will flip TF bit before returning.
0040  *
0041  * Note: it should be installed as raw interrupt handler.
0042  *
0043  * Warning: I do not like the use of the global data, I am not
0044  *          sure if this is SMP safe.
0045  */
0046 int i386_gdb_uart_isr_regsav[4] RTEMS_UNUSED;
0047 __asm__ (".p2align 4");
0048 __asm__ (".text");
0049 __asm__ (".globl i386_gdb_uart_isr");
0050 __asm__ ("i386_gdb_uart_isr:");
0051 __asm__ ("    pusha");                                       /* Push all */
0052 __asm__ ("    call  i386_gdb_uart_ctrl_c_check");            /* Look for ^C */
0053 __asm__ ("    movl  %eax, i386_gdb_uart_isr_regsav");        /* Save eax */
0054 __asm__ ("    popa");                                        /* Pop all */
0055 __asm__ ("    xchgl %eax, i386_gdb_uart_isr_regsav");        /* Exchange eax */
0056 __asm__ ("    cmpl  $0, %eax");                              /* 1 == ^C */
0057 __asm__ ("    je    i386_gdb_uart_isr_1");                   /* branch if 0 */
0058 __asm__ ("    movl  %ebx, i386_gdb_uart_isr_regsav + 4");    /* Save ebx */
0059 __asm__ ("    movl  %edx, i386_gdb_uart_isr_regsav + 8");    /* Save edx */
0060 __asm__ ("    popl  %ebx");                                  /* Pop eip */
0061 __asm__ ("    popl  %edx");                                  /* Pop cs */
0062 __asm__ ("    popl  %eax");                                  /* Pop flags */
0063 __asm__ ("    orl   $0x100, %eax");                          /* Modify it */
0064 __asm__ ("    pushl %eax");                                  /* Push it back */
0065 __asm__ ("    pushl %edx");                                  /* Push cs */
0066 __asm__ ("    pushl %ebx");                                  /* Push eip */
0067 __asm__ ("    movl  i386_gdb_uart_isr_regsav + 4, %ebx");    /* Restore ebx */
0068 __asm__ ("    movl  i386_gdb_uart_isr_regsav + 8, %edx");    /* Restore edx */
0069 __asm__ ("i386_gdb_uart_isr_1:");
0070 __asm__ ("    movl  i386_gdb_uart_isr_regsav, %eax");        /* Restore eax */
0071 __asm__ ("    iret");                                        /* Done */
0072 
0073 static int gdb_hello_index;
0074 static const char *const gdb_hello = "+";
0075 
0076 static inline uint8_t BSP_i8259a_irq_in_service_reg(uint32_t ioport)
0077 {
0078   uint8_t isr;
0079   outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR | PIC_OCW3_RIS);
0080   inport_byte(ioport, isr);
0081   outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR);
0082   return isr;
0083 }
0084 
0085 static inline void BSP_irq_ack_at_i8259a(const int irqLine)
0086 {
0087   uint8_t slave_isr = 0;
0088   if (irqLine >= 8) {
0089    outport_byte(PIC_SLAVE_COMMAND_IO_PORT, PIC_EOI);
0090    slave_isr = BSP_i8259a_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT);
0091   }
0092 
0093   /*
0094    * Only issue the EOI to the master if there are no more interrupts in
0095    * service for the slave. i8259a data sheet page 18, The Special Fully Nested
0096    * Mode, b.
0097    */
0098   if (slave_isr == 0)
0099     outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI);
0100 }
0101 
0102 int i386_gdb_uart_ctrl_c_check(void)
0103 {
0104   BSP_irq_ack_at_i8259a(uart_vector);
0105   if (port_current) {
0106     int c = 0;
0107     while (c >= 0) {
0108       c = port_current->pDeviceFns->deviceRead(uart_current);
0109       if (c == 3) {
0110         gdb_hello_index = 0;
0111         return 1;
0112       } else if (gdb_hello[gdb_hello_index] == (char) c) {
0113         ++gdb_hello_index;
0114         if (gdb_hello[gdb_hello_index] == '\0') {
0115           gdb_hello_index = 0;
0116           return 1;
0117         }
0118       } else {
0119         gdb_hello_index = 0;
0120       }
0121     }
0122   }
0123   return 0;
0124 }
0125 
0126 static void
0127 nop(const rtems_raw_irq_connect_data* notused)
0128 {
0129 }
0130 
0131 static int
0132 isOn(const rtems_raw_irq_connect_data* notused)
0133 {
0134   return 1;
0135 }
0136 
0137 int i386_stub_glue_uart(void)
0138 {
0139   if (port_current == NULL)
0140     return -1;
0141   return uart_current;
0142 }
0143 
0144 /*
0145  * Initialize glue code linking i386-stub with the rest of
0146  * the system
0147  */
0148 void
0149 i386_stub_glue_init(int uart)
0150 {
0151   rtems_device_minor_number minor = (rtems_device_minor_number) uart;
0152 
0153   port_current = console_find_console_entry(NULL, 0, &minor);
0154 
0155   if (port_current == NULL) {
0156     printk("GDB: invalid minor number for UART\n");
0157     return;
0158   }
0159 
0160   uart_current = uart;
0161 
0162   /* Intialise the UART, assuming polled drivers */
0163   port_current->pDeviceFns->deviceInitialize(uart);
0164 }
0165 
0166 static void BSP_uart_on(const rtems_raw_irq_connect_data* used)
0167 {
0168   bsp_interrupt_vector_enable(used->idtIndex - BSP_IRQ_VECTOR_BASE);
0169 }
0170 
0171 static void BSP_uart_off(const rtems_raw_irq_connect_data* used)
0172 {
0173   bsp_interrupt_vector_disable(used->idtIndex - BSP_IRQ_VECTOR_BASE);
0174 }
0175 
0176 /*
0177  * In order to have a possibility to break into
0178  * running program, one has to call this function
0179  */
0180 void i386_stub_glue_init_breakin(void)
0181 {
0182   rtems_raw_irq_connect_data uart_raw_irq_data;
0183 
0184   if (port_current == NULL) {
0185     printk("GDB: no port initialised\n");
0186     return;
0187   }
0188 
0189   if ((port_current->ulIntVector == 0) || (port_current->ulIntVector > 16)) {
0190     printk("GDB: no UART interrupt support\n");
0191   }
0192   else {
0193     uart_vector = port_current->ulIntVector;
0194     uart_raw_irq_data.idtIndex = port_current->ulIntVector + BSP_IRQ_VECTOR_BASE;
0195 
0196     if (!i386_get_current_idt_entry(&uart_raw_irq_data)) {
0197       printk("GBD: cannot get idt entry\n");
0198       rtems_fatal_error_occurred(1);
0199     }
0200 
0201     if (!i386_delete_idt_entry(&uart_raw_irq_data)) {
0202       printk("GDB: cannot delete idt entry\n");
0203       rtems_fatal_error_occurred(1);
0204     }
0205 
0206     uart_raw_irq_data.on  = BSP_uart_on;
0207     uart_raw_irq_data.off = BSP_uart_off;
0208 
0209     /* Install ISR  */
0210     uart_raw_irq_data.idtIndex = port_current->ulIntVector + BSP_IRQ_VECTOR_BASE;
0211     uart_raw_irq_data.hdl = i386_gdb_uart_isr;
0212 
0213     if (!i386_set_idt_entry (&uart_raw_irq_data)) {
0214       printk("GDB: raw exception handler connection failed\n");
0215       rtems_fatal_error_occurred(1);
0216     }
0217 
0218     /* Enable interrupts, this is a bit of a hack because we
0219      * have to know the device but there is no other call. */
0220     (*port_current->setRegister)(port_current->ulCtrlPort1, 1, 0x01);
0221   }
0222 }
0223 
0224 int
0225 putDebugChar(int ch)
0226 {
0227   if (port_current != NULL) {
0228     port_current->pDeviceFns->deviceWritePolled(uart_current, ch);
0229   }
0230   return 1;
0231 }
0232 
0233 int getDebugChar(void)
0234 {
0235   int c = -1;
0236 
0237   if (port_current != NULL) {
0238     while (c < 0)
0239       c = port_current->pDeviceFns->deviceRead(uart_current);
0240   }
0241 
0242   return c;
0243 }
0244 
0245 void exceptionHandler(int vector, void (*handler)(void))
0246 {
0247   rtems_raw_irq_connect_data excep_raw_irq_data;
0248 
0249   excep_raw_irq_data.idtIndex = vector;
0250 
0251   if(!i386_get_current_idt_entry(&excep_raw_irq_data))
0252     {
0253       printk("GDB: cannot get idt entry\n");
0254       rtems_fatal_error_occurred(1);
0255     }
0256 
0257   if(!i386_delete_idt_entry(&excep_raw_irq_data))
0258     {
0259       printk("GDB: cannot delete idt entry\n");
0260       rtems_fatal_error_occurred(1);
0261     }
0262 
0263   excep_raw_irq_data.on = nop;
0264   excep_raw_irq_data.off = nop;
0265   excep_raw_irq_data.isOn = isOn;
0266   excep_raw_irq_data.hdl = handler;
0267 
0268   if (!i386_set_idt_entry (&excep_raw_irq_data)) {
0269       printk("GDB: raw exception handler connection failed\n");
0270       rtems_fatal_error_occurred(1);
0271     }
0272   return;
0273 }