source: rtems/c/src/lib/libbsp/i386/shared/comm/i386-stub-glue.c @ fc138a10

Last change on this file since fc138a10 was fc138a10, checked in by Chris Johns <chrisj@…>, on May 6, 2016 at 10:17:51 PM

i386/pc386: EOI the master and slave for slave IRQ signals.

  • Property mode set to 100644
File size: 8.0 KB
Line 
1/*
2 * Copyright (c) 2016.
3 * Chris Johns <chrisj@rtems.org>
4 *
5 * This software is Copyright (C) 1998 by T.sqware - all rights limited
6 * It is provided in to the public domain "as is", can be freely modified
7 * as far as this copyight notice is kept unchanged, but does not imply
8 * an endorsement by T.sqware of the product in which it is included.
9 */
10
11#include <bsp.h>
12#include <bsp/irq-generic.h>
13#include <libchip/serial.h>
14
15#include "../../../shared/console_private.h"
16
17int  putDebugChar(int ch);     /* write a single character      */
18int  getDebugChar(void);       /* read and return a single char */
19
20/* Check is any characters received are a ^C */
21int i386_gdb_uart_ctrl_c_check(void);
22
23/* Raw interrupt handler. */
24void i386_gdb_uart_isr(void);
25
26/* assign an exception handler */
27void exceptionHandler(int, void (*handler)(void));
28
29/* User supplied remote debug option. */
30extern int remote_debug;
31
32/* Current uart and port used by the gdb stub */
33static int          uart_current;
34static int          uart_vector;
35static console_tbl* port_current;
36
37/*
38 * Interrupt service routine for all, it does it check whether ^C is received
39 * if yes it will flip TF bit before returning.
40 *
41 * Note: it should be installed as raw interrupt handler.
42 *
43 * Warning: I do not like the use of the global data, I am not
44 *          sure if this is SMP safe.
45 */
46int i386_gdb_uart_isr_regsav[4] RTEMS_UNUSED;
47__asm__ (".p2align 4");
48__asm__ (".text");
49__asm__ (".globl i386_gdb_uart_isr");
50__asm__ ("i386_gdb_uart_isr:");
51__asm__ ("    pusha");                                       /* Push all */
52__asm__ ("    call  i386_gdb_uart_ctrl_c_check");            /* Look for ^C */
53__asm__ ("    movl  %eax, i386_gdb_uart_isr_regsav");        /* Save eax */
54__asm__ ("    popa");                                        /* Pop all */
55__asm__ ("    xchgl %eax, i386_gdb_uart_isr_regsav");        /* Exchange eax */
56__asm__ ("    cmpl  $0, %eax");                              /* 1 == ^C */
57__asm__ ("    je    i386_gdb_uart_isr_1");                   /* branch if 0 */
58__asm__ ("    movl  %ebx, i386_gdb_uart_isr_regsav + 4");    /* Save ebx */
59__asm__ ("    movl  %edx, i386_gdb_uart_isr_regsav + 8");    /* Save edx */
60__asm__ ("    popl  %ebx");                                  /* Pop eip */
61__asm__ ("    popl  %edx");                                  /* Pop cs */
62__asm__ ("    popl  %eax");                                  /* Pop flags */
63__asm__ ("    orl   $0x100, %eax");                          /* Modify it */
64__asm__ ("    pushl %eax");                                  /* Push it back */
65__asm__ ("    pushl %edx");                                  /* Push cs */
66__asm__ ("    pushl %ebx");                                  /* Push eip */
67__asm__ ("    movl  i386_gdb_uart_isr_regsav + 4, %ebx");    /* Restore ebx */
68__asm__ ("    movl  i386_gdb_uart_isr_regsav + 8, %edx");    /* Restore edx */
69__asm__ ("i386_gdb_uart_isr_1:");
70__asm__ ("    movl  i386_gdb_uart_isr_regsav, %eax");        /* Restore eax */
71__asm__ ("    iret");                                        /* Done */
72
73static int gdb_hello_index;
74static const char const* gdb_hello = "+";
75
76static inline uint8_t BSP_i8259a_irq_in_service_reg(uint32_t ioport)
77{
78  uint8_t isr;
79  outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR | PIC_OCW3_RIS);
80  inport_byte(ioport, isr);
81  outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR);
82  return isr;
83}
84
85static inline void BSP_irq_ack_at_i8259a(const int irqLine)
86{
87  uint8_t slave_isr = 0;
88  if (irqLine >= 8) {
89   outport_byte(PIC_SLAVE_COMMAND_IO_PORT, PIC_EOI);
90   slave_isr = BSP_i8259a_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT);
91  }
92
93  /*
94   * Only issue the EOI to the master if there are no more interrupts in
95   * service for the slave. i8259a data sheet page 18, The Special Fully Nested
96   * Mode, b.
97   */
98  if (slave_isr == 0)
99    outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI);
100}
101
102int i386_gdb_uart_ctrl_c_check(void)
103{
104  BSP_irq_ack_at_i8259a(uart_vector);
105  if (port_current) {
106    int c = 0;
107    while (c >= 0) {
108      c = port_current->pDeviceFns->deviceRead(uart_current);
109      if (c == 3) {
110        gdb_hello_index = 0;
111        return 1;
112      } else if (gdb_hello[gdb_hello_index] == (char) c) {
113        ++gdb_hello_index;
114        if (gdb_hello[gdb_hello_index] == '\0') {
115          gdb_hello_index = 0;
116          return 1;
117        }
118      } else {
119        gdb_hello_index = 0;
120      }
121    }
122  }
123  return 0;
124}
125
126static void
127nop(const rtems_raw_irq_connect_data* notused)
128{
129}
130
131static int
132isOn(const rtems_raw_irq_connect_data* notused)
133{
134  return 1;
135}
136
137int i386_stub_glue_uart(void)
138{
139  if (port_current == NULL)
140    return -1;
141  return uart_current;
142}
143
144/*
145 * Initialize glue code linking i386-stub with the rest of
146 * the system
147 */
148void
149i386_stub_glue_init(int uart)
150{
151  rtems_device_minor_number minor = (rtems_device_minor_number) uart;
152
153  port_current = console_find_console_entry(NULL, 0, &minor);
154
155  if (port_current == NULL) {
156    printk("GDB: invalid minor number for UART\n");
157    return;
158  }
159
160  uart_current = uart;
161
162  /* Intialise the UART, assuming polled drivers */
163  port_current->pDeviceFns->deviceInitialize(uart);
164}
165
166static void BSP_uart_on(const rtems_raw_irq_connect_data* used)
167{
168  bsp_interrupt_vector_enable(used->idtIndex - BSP_IRQ_VECTOR_BASE);
169}
170
171static void BSP_uart_off(const rtems_raw_irq_connect_data* used)
172{
173  bsp_interrupt_vector_disable(used->idtIndex - BSP_IRQ_VECTOR_BASE);
174}
175
176static int BSP_uart_isOn(const rtems_raw_irq_connect_data* used)
177{
178  return bsp_interrupt_vector_enable(used->idtIndex - BSP_IRQ_VECTOR_BASE);
179}
180
181/*
182 * In order to have a possibility to break into
183 * running program, one has to call this function
184 */
185void i386_stub_glue_init_breakin(void)
186{
187  rtems_raw_irq_connect_data uart_raw_irq_data;
188
189  if (port_current == NULL) {
190    printk("GDB: no port initialised\n");
191    return;
192  }
193
194  if ((port_current->ulIntVector == 0) || (port_current->ulIntVector > 16)) {
195    printk("GDB: no UART interrupt support\n");
196  }
197  else {
198    uart_vector = port_current->ulIntVector;
199    uart_raw_irq_data.idtIndex = port_current->ulIntVector + BSP_IRQ_VECTOR_BASE;
200
201    if (!i386_get_current_idt_entry(&uart_raw_irq_data)) {
202      printk("GBD: cannot get idt entry\n");
203      rtems_fatal_error_occurred(1);
204    }
205
206    if (!i386_delete_idt_entry(&uart_raw_irq_data)) {
207      printk("GDB: cannot delete idt entry\n");
208      rtems_fatal_error_occurred(1);
209    }
210
211    uart_raw_irq_data.on  = BSP_uart_on;
212    uart_raw_irq_data.off = BSP_uart_off;
213    uart_raw_irq_data.isOn= BSP_uart_isOn;
214
215    /* Install ISR  */
216    uart_raw_irq_data.idtIndex = port_current->ulIntVector + BSP_IRQ_VECTOR_BASE;
217    uart_raw_irq_data.hdl = i386_gdb_uart_isr;
218
219    if (!i386_set_idt_entry (&uart_raw_irq_data)) {
220      printk("GDB: raw exception handler connection failed\n");
221      rtems_fatal_error_occurred(1);
222    }
223
224    /* Enable interrupts, this is a bit of a hack because we
225     * have to know the device but there is no other call. */
226    (*port_current->setRegister)(port_current->ulCtrlPort1, 1, 0x01);
227  }
228}
229
230int
231putDebugChar(int ch)
232{
233  if (port_current != NULL) {
234    port_current->pDeviceFns->deviceWritePolled(uart_current, ch);
235  }
236  return 1;
237}
238
239int getDebugChar(void)
240{
241  int c = -1;
242
243  if (port_current != NULL) {
244    while (c < 0)
245      c = port_current->pDeviceFns->deviceRead(uart_current);
246  }
247
248  return c;
249}
250
251void exceptionHandler(int vector, void (*handler)(void))
252{
253  rtems_raw_irq_connect_data excep_raw_irq_data;
254
255  excep_raw_irq_data.idtIndex = vector;
256
257  if(!i386_get_current_idt_entry(&excep_raw_irq_data))
258    {
259      printk("GDB: cannot get idt entry\n");
260      rtems_fatal_error_occurred(1);
261    }
262
263  if(!i386_delete_idt_entry(&excep_raw_irq_data))
264    {
265      printk("GDB: cannot delete idt entry\n");
266      rtems_fatal_error_occurred(1);
267    }
268
269  excep_raw_irq_data.on = nop;
270  excep_raw_irq_data.off = nop;
271  excep_raw_irq_data.isOn = isOn;
272  excep_raw_irq_data.hdl = handler;
273
274  if (!i386_set_idt_entry (&excep_raw_irq_data)) {
275      printk("GDB: raw exception handler connection failed\n");
276      rtems_fatal_error_occurred(1);
277    }
278  return;
279}
Note: See TracBrowser for help on using the repository browser.