FreeBASIC  0.91.0
sys_isr.c
Go to the documentation of this file.
1 /* ISR handling for DOS */
2 
3 #include "../fb.h"
4 #include <dpmi.h>
5 #include <go32.h>
6 #include <pc.h>
7 
8 typedef struct _FB_DOS_STACK_INFO {
9  void *offset;
10  size_t size;
12 
13 static int isr_inited = FALSE;
14 static size_t function_sizes[16] = { 0 };
15 
16 /* This is the code layout for isr.S */
17 extern char __fb_hDrvIntHandler_start;
18 extern __dpmi_paddr __fb_hDrvIntHandler_OldIRQs[16];
21 extern unsigned __fb_hDrvSelectors[5];
22 extern int __fb_dos_cli_level;
23 void __fb_hDrvIntHandler_PIC1(void);
24 void __fb_hDrvIntHandler_PIC2(void);
25 extern char __fb_hDrvIntHandler_end;
26 
30 #define fb_lock_memory_fn( fn_name ) \
31  fb_dos_lock_code( fn_name, fn_name ## _end - fn_name )
32 
33 #define fb_lock_memory_data( var_name ) \
34  fb_dos_lock_data( &var_name ## _start, &var_name ## _end - &var_name ## _start )
35 
36 static int do_lock(int is_code, int (*proc)(__dpmi_meminfo *), const void *address, size_t size)
37 {
38  unsigned long base;
39  __dpmi_meminfo mi;
40 
41  if ( __dpmi_get_segment_base_address( is_code ? _go32_my_cs() : _go32_my_ds(), &base ) == -1 )
42  return -1;
43 
44  mi.address = base + (unsigned long)address;
45  mi.size = size;
46 
47  return proc( &mi );
48 }
49 
50 int fb_dos_lock_data(const void *address, size_t size)
51 {
52  return do_lock(FALSE, __dpmi_lock_linear_region, address, size);
53 }
54 
55 int fb_dos_lock_code(const void *address, size_t size)
56 {
57  return do_lock(TRUE, __dpmi_lock_linear_region, address, size);
58 }
59 
60 int fb_dos_unlock_data(const void *address, size_t size)
61 {
62  return do_lock(FALSE, __dpmi_unlock_linear_region, address, size);
63 }
64 
65 int fb_dos_unlock_code(const void *address, size_t size)
66 {
67  return do_lock(TRUE, __dpmi_unlock_linear_region, address, size);
68 }
69 
70 static __inline__ int
71 _my_es(void)
72 {
73  unsigned short result;
74  __asm__("movw %%es,%0" : "=r" (result));
75  return result;
76 }
77 
78 static __inline__ int
79 _my_fs(void)
80 {
81  unsigned short result;
82  __asm__("movw %%fs,%0" : "=r" (result));
83  return result;
84 }
85 
86 static __inline__ int
87 _my_gs(void)
88 {
89  unsigned short result;
90  __asm__("movw %%gs,%0" : "=r" (result));
91  return result;
92 }
93 
94 static void fb_isr_exit(void)
95 {
96  __dpmi_version_ret version;
97  int i;
98 
99  FB_LOCK();
100  if( !isr_inited ) {
101  FB_UNLOCK();
102  return;
103  }
104 
105  /* query DPMI version */
106  if( __dpmi_get_version( &version )!=0 ) {
107  FB_UNLOCK();
108  abort();
109  }
110 
111  fb_dos_cli();
112 
113  /* restore ISR offsets for master PIC */
114  for( i=0; i!=8; ++i ) {
115  int irq_vector = version.master_pic + i;
116  __dpmi_paddr *offset = __fb_hDrvIntHandler_OldIRQs + i;
117  if( __dpmi_set_protected_mode_interrupt_vector( irq_vector, offset ) != 0 ) {
118  FB_UNLOCK();
119  abort();
120  return;
121  }
122  }
123 
124  /* restore ISR offsets for slave PIC */
125  for( i=0; i!=8; ++i ) {
126  int irq_vector = version.slave_pic + i;
127  __dpmi_paddr *offset = __fb_hDrvIntHandler_OldIRQs + i + 8;
128  if( __dpmi_set_protected_mode_interrupt_vector( irq_vector, offset ) != 0 ) {
129  FB_UNLOCK();
130  abort();
131  }
132  }
133 
134  fb_dos_sti();
135 
136  isr_inited = FALSE;
137 
138  FB_UNLOCK();
139 }
140 
141 static int fb_isr_init(void)
142 {
143  __dpmi_version_ret version;
144  int succeeded;
145  size_t i, j;
146 
147  FB_LOCK();
148  if( isr_inited ) {
149  FB_UNLOCK();
150  return TRUE;
151  }
152 
153  /* store all selectors */
154  __fb_hDrvSelectors[0] = _my_ds();
155  __fb_hDrvSelectors[1] = _my_es();
156  __fb_hDrvSelectors[2] = _my_fs();
157  __fb_hDrvSelectors[3] = _my_gs();
158  __fb_hDrvSelectors[4] = _my_ss();
159 
160  /* query DPMI version */
161  if( __dpmi_get_version( &version )!=0 ) {
162  FB_UNLOCK();
163  return FALSE;
164  }
165 
166  /* query ISR offsets for master PIC */
167  for( i=0; i!=8; ++i ) {
168  int irq_vector = version.master_pic + i;
169  __dpmi_paddr *offset = __fb_hDrvIntHandler_OldIRQs + i;
170  if( __dpmi_get_protected_mode_interrupt_vector( irq_vector, offset ) != 0 ) {
171  FB_UNLOCK();
172  return FALSE;
173  }
174  }
175 
176  /* query ISR offsets for slave PIC */
177  for( i=0; i!=8; ++i ) {
178  int irq_vector = version.slave_pic + i;
179  __dpmi_paddr *offset = __fb_hDrvIntHandler_OldIRQs + i + 8;
180  if( __dpmi_get_protected_mode_interrupt_vector( irq_vector, offset ) != 0 ) {
181  FB_UNLOCK();
182  return FALSE;
183  }
184  }
185 
186  /* lock all generic ISR code/data */
188  FB_UNLOCK();
189  return FALSE;
190  }
191 
192 
193  fb_dos_cli();
194  succeeded = TRUE;
195  /* Redirection for PIC1 */
196  for( i=0; i!=8; ++i ) {
197  int irq_vector = version.master_pic + i;
198  __dpmi_paddr offset = {
199  (unsigned long) __fb_hDrvIntHandler_PIC1,
200  (unsigned short) _my_cs()
201  };
202  if( __dpmi_set_protected_mode_interrupt_vector( irq_vector, &offset )!=0 ) {
203  /* When an error occurred, restore the old ISR offsets */
204  for( j=0; j!=i; ++j ) {
205  int irq_vector = version.master_pic + j;
206  __dpmi_paddr *offset = __fb_hDrvIntHandler_OldIRQs + j;
207  __dpmi_set_protected_mode_interrupt_vector( irq_vector, offset );
208  }
209  succeeded = FALSE;
210  break;
211  }
212  }
213  if( succeeded ) {
214  /* Redirection for PIC2 */
215  for( i=0; i!=8; ++i ) {
216  int irq_vector = version.slave_pic + i;
217  __dpmi_paddr offset = {
218  (unsigned long) __fb_hDrvIntHandler_PIC2,
219  (unsigned short) _my_cs()
220  };
221  if( __dpmi_set_protected_mode_interrupt_vector( irq_vector, &offset )!=0 ) {
222  /* When an error occurred, restore the old ISR offsets
223  * for both the master and the slave PIC */
224  for( j=0; j!=8; ++j ) {
225  int irq_vector = version.master_pic + j;
226  __dpmi_paddr *offset = __fb_hDrvIntHandler_OldIRQs + j;
227  __dpmi_set_protected_mode_interrupt_vector( irq_vector, offset );
228  }
229  for( j=0; j!=i; ++j ) {
230  int irq_vector = version.slave_pic + j;
231  __dpmi_paddr *offset = __fb_hDrvIntHandler_OldIRQs + j + 8;
232  __dpmi_set_protected_mode_interrupt_vector( irq_vector, offset );
233  }
234  succeeded = FALSE;
235  break;
236  }
237  }
238  }
239  fb_dos_sti();
240 
241  if( !succeeded ) {
242  FB_UNLOCK();
243  return FALSE;
244  }
245 
246  isr_inited = TRUE;
247  atexit( fb_isr_exit );
248 
249  FB_UNLOCK();
250 
251  return TRUE;
252 }
253 
254 int fb_isr_set( unsigned irq_number,
255  FnIntHandler pfnIntHandler,
256  size_t fn_size,
257  size_t stack_size )
258 {
259  void *pStack;
260  DBG_ASSERT( irq_number < 16 );
261 
262  if( !fb_isr_init() )
263  return FALSE;
264 
265  if( __fb_hDrvIntHandler[irq_number]!=NULL )
266  fb_isr_reset( irq_number );
267 
268  if( fb_dos_lock_code( pfnIntHandler, fn_size )!=0 )
269  return FALSE;
270 
271  if( stack_size!=0 ) {
272  if( stack_size < _go32_interrupt_stack_size )
273  stack_size = _go32_interrupt_stack_size;
274  if( stack_size < 512 )
275  stack_size = 512;
276 
277  pStack = malloc( stack_size );
278  if( pStack==NULL )
279  return FALSE;
280 
281  if( fb_dos_lock_data( pStack, stack_size )!=0 ) {
282  free( pStack );
283  return FALSE;
284  }
285  } else {
286  pStack = NULL;
287  }
288 
289  fb_dos_cli();
290  function_sizes[irq_number] = fn_size;
291  __fb_hDrvIntHandler[irq_number] = pfnIntHandler;
292  __fb_hDrvIntStacks[irq_number].offset = pStack;
293  __fb_hDrvIntStacks[irq_number].size = stack_size;
294  fb_dos_sti();
295 
296  return TRUE;
297 }
298 
299 int fb_isr_reset( unsigned irq_number )
300 {
301  DBG_ASSERT( irq_number < 16 );
302 
303  if( !fb_isr_init() )
304  return FALSE;
305 
306  if( __fb_hDrvIntHandler[irq_number]!=NULL ) {
307  void *pStack;
308  size_t stack_size;
309  FnIntHandler pfnIntHandler;
310  size_t fn_size;
311 
312  fb_dos_cli();
313  pfnIntHandler = __fb_hDrvIntHandler[irq_number];
314  fn_size = function_sizes[irq_number];
315  __fb_hDrvIntHandler[irq_number] = NULL;
316  function_sizes[irq_number] = 0;
317 
318  pStack = __fb_hDrvIntStacks[irq_number].offset;
319  stack_size = __fb_hDrvIntStacks[irq_number].size;
320  __fb_hDrvIntStacks[irq_number].offset = NULL;
321  __fb_hDrvIntStacks[irq_number].size = 0;
322  fb_dos_sti();
323 
324  fb_dos_unlock_code( pfnIntHandler, fn_size );
325  fb_dos_unlock_data( pStack, stack_size );
326 
327  free( pStack );
328  }
329 
330  return TRUE;
331 }
332 
333 FnIntHandler fb_isr_get( unsigned irq_number )
334 {
335  DBG_ASSERT( irq_number < 16 );
336  return __fb_hDrvIntHandler[irq_number];
337 }