Changeset 637df35 in rtems for cpukit/score/cpu/unix
- Timestamp:
- Jul 12, 1995, 7:47:25 PM (26 years ago)
- Branches:
- 4.10, 4.11, 4.8, 4.9, 5, master
- Children:
- 6cc85032
- Parents:
- 68931b5
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
cpukit/score/cpu/unix/cpu.c
r68931b5 r637df35 18 18 19 19 #include <rtems/system.h> 20 #include <rtems/fatal.h>21 20 #include <rtems/isr.h> 22 #include <rtems/wkspace.h>23 /*24 * In order to get the types and prototypes used in this file under25 * Solaris 2.3, it is necessary to pull the following magic.26 */27 28 #if defined(solaris)29 #warning "Ignore the undefining __STDC__ warning"30 #undef __STDC__31 #define __STDC__ 032 #undef _POSIX_C_SOURCE33 #endif34 21 35 22 #include <stdio.h> … … 39 26 #include <time.h> 40 27 41 extern void set_vector(proc_ptr, int, int); 42 extern void _Thread_Dispatch(void); 43 44 extern unsigned32 _Thread_Dispatch_disable_level; 45 extern unsigned32 _SYSTEM_ID; 46 extern boolean _Context_Switch_necessary; 47 48 49 rtems_status_code signal_initialize(void); 50 void Stray_signal(int); 51 void signal_enable(unsigned32); 52 void signal_disable(unsigned32); 53 void interrupt_handler(); 54 55 sigset_t UNIX_SIGNAL_MASK; 56 jmp_buf default_context; 28 #ifndef SA_RESTART 29 #define SA_RESTART 0 30 #endif 31 32 void _CPU_Signal_initialize(void); 33 void _CPU_Stray_signal(int); 34 void _CPU_ISR_Handler(int); 35 36 sigset_t _CPU_Signal_mask; 37 Context_Control _CPU_Context_Default_with_ISRs_enabled; 38 Context_Control _CPU_Context_Default_with_ISRs_disabled; 57 39 58 40 /* … … 61 43 62 44 int cpu_number; 45 46 /*PAGE 47 * 48 * _CPU_ISR_From_CPU_Init 49 */ 50 51 void _CPU_ISR_From_CPU_Init() 52 { 53 unsigned32 i; 54 proc_ptr old_handler; 55 56 57 /* 58 * Block all the signals except SIGTRAP for the debugger 59 * and SIGABRT for fatal errors. 60 */ 61 62 _CPU_ISR_Enable(1); 63 64 (void) sigfillset(&_CPU_Signal_mask); 65 (void) sigdelset(&_CPU_Signal_mask, SIGTRAP); 66 (void) sigdelset(&_CPU_Signal_mask, SIGABRT); 67 (void) sigdelset(&_CPU_Signal_mask, SIGIOT); 68 (void) sigdelset(&_CPU_Signal_mask, SIGCONT); 69 70 sigprocmask(SIG_BLOCK, &_CPU_Signal_mask, 0); 71 72 /* 73 * Set the handler for all signals to be signal_handler 74 * which will then vector out to the correct handler 75 * for whichever signal actually happened. Initially 76 * set the vectors to the stray signal handler. 77 */ 78 79 for (i = 0; i < CPU_INTERRUPT_NUMBER_OF_VECTORS; i++) 80 (void)_CPU_ISR_install_vector(i, _CPU_Stray_signal, &old_handler); 81 82 _CPU_Signal_initialize(); 83 } 84 85 void _CPU_Signal_initialize( void ) 86 { 87 struct sigaction act; 88 sigset_t mask; 89 90 /* mark them all active except for TraceTrap and Abort */ 91 92 sigfillset(&mask); 93 sigdelset(&mask, SIGTRAP); 94 sigdelset(&mask, SIGABRT); 95 sigdelset(&mask, SIGIOT); 96 sigdelset(&mask, SIGCONT); 97 sigprocmask(SIG_UNBLOCK, &mask, 0); 98 99 act.sa_handler = _CPU_ISR_Handler; 100 act.sa_mask = mask; 101 act.sa_flags = SA_RESTART; 102 103 sigaction(SIGHUP, &act, 0); 104 sigaction(SIGINT, &act, 0); 105 sigaction(SIGQUIT, &act, 0); 106 sigaction(SIGILL, &act, 0); 107 sigaction(SIGEMT, &act, 0); 108 sigaction(SIGFPE, &act, 0); 109 sigaction(SIGKILL, &act, 0); 110 sigaction(SIGBUS, &act, 0); 111 sigaction(SIGSEGV, &act, 0); 112 sigaction(SIGSYS, &act, 0); 113 sigaction(SIGPIPE, &act, 0); 114 sigaction(SIGALRM, &act, 0); 115 sigaction(SIGTERM, &act, 0); 116 sigaction(SIGUSR1, &act, 0); 117 sigaction(SIGUSR2, &act, 0); 118 sigaction(SIGCHLD, &act, 0); 119 sigaction(SIGCLD, &act, 0); 120 sigaction(SIGPWR, &act, 0); 121 sigaction(SIGVTALRM, &act, 0); 122 sigaction(SIGPROF, &act, 0); 123 sigaction(SIGIO, &act, 0); 124 sigaction(SIGWINCH, &act, 0); 125 sigaction(SIGSTOP, &act, 0); 126 sigaction(SIGTTIN, &act, 0); 127 sigaction(SIGTTOU, &act, 0); 128 sigaction(SIGURG, &act, 0); 129 /* 130 * XXX: Really should be on HPUX. 131 */ 132 133 #if defined(hppa1_1) 134 sigaction(SIGLOST, &act, 0); 135 #endif 136 137 } 138 139 /*PAGE 140 * 141 * _CPU_Context_From_CPU_Init 142 */ 143 144 void _CPU_Context_From_CPU_Init() 145 { 146 147 #if defined(hppa1_1) && defined(RTEMS_UNIXLIB) 148 /* 149 * HACK - set the _SYSTEM_ID to 0x20c so that setjmp/longjmp 150 * will handle the full 32 floating point registers. 151 * 152 * NOTE: Is this a bug in HPUX9? 153 */ 154 155 { 156 extern unsigned32 _SYSTEM_ID; 157 158 _SYSTEM_ID = 0x20c; 159 } 160 #endif 161 162 /* 163 * get default values to use in _CPU_Context_Initialize() 164 */ 165 166 _CPU_ISR_Set_level( 0 ); 167 setjmp( _CPU_Context_Default_with_ISRs_enabled.regs ); 168 sigprocmask( 169 SIG_SETMASK, /* ignored when second arg is NULL */ 170 0, 171 &_CPU_Context_Default_with_ISRs_enabled.isr_level 172 ); 173 174 _CPU_ISR_Set_level( 1 ); 175 setjmp( _CPU_Context_Default_with_ISRs_disabled.regs ); 176 sigprocmask( 177 SIG_SETMASK, /* ignored when second arg is NULL */ 178 0, 179 &_CPU_Context_Default_with_ISRs_disabled.isr_level 180 ); 181 182 } 63 183 64 184 /* _CPU_Initialize … … 77 197 ) 78 198 { 79 unsigned32 i;80 81 199 if ( cpu_table == NULL ) 82 rtems_fatal_error_occurred( RTEMS_NOT_CONFIGURED );200 _CPU_Fatal_halt( RTEMS_NOT_CONFIGURED ); 83 201 84 202 /* … … 106 224 _CPU_Table = *cpu_table; 107 225 108 #if defined(hppa1_1) && defined(RTEMS_UNIXLIB) 109 /* 110 * HACK - set the _SYSTEM_ID to 0x20c so that setjmp/longjmp 111 * will handle the full 32 floating point registers. 112 * 113 * NOTE: Is this a bug in HPUX9? 114 */ 115 116 _SYSTEM_ID = 0x20c; 117 #endif 118 119 /* 120 * get default values to use in _CPU_Context_Initialize() 121 */ 122 123 setjmp(default_context); 124 125 /* 126 * Block all the signals except SIGTRAP for the debugger 127 * and SIGABRT for fatal errors. 128 */ 129 130 _CPU_ISR_Set_signal_level(1); 131 132 sigfillset(&UNIX_SIGNAL_MASK); 133 sigdelset(&UNIX_SIGNAL_MASK, SIGTRAP); 134 sigdelset(&UNIX_SIGNAL_MASK, SIGABRT); 135 sigdelset(&UNIX_SIGNAL_MASK, SIGIOT); 136 sigdelset(&UNIX_SIGNAL_MASK, SIGCONT); 137 138 sigprocmask(SIG_BLOCK, &UNIX_SIGNAL_MASK, 0); 139 140 /* 141 * Set the handler for all signals to be signal_handler 142 * which will then vector out to the correct handler 143 * for whichever signal actually happened. Initially 144 * set the vectors to the stray signal handler. 145 */ 146 147 for (i = 0; i < 32; i++) 148 (void)set_vector(Stray_signal, i, 1); 149 150 signal_initialize(); 151 } 152 153 /* _CPU_ISR_install_vector 226 _CPU_ISR_From_CPU_Init(); 227 228 _CPU_Context_From_CPU_Init(); 229 230 } 231 232 /*PAGE 233 * 234 * _CPU_ISR_install_raw_handler 235 */ 236 237 void _CPU_ISR_install_raw_handler( 238 unsigned32 vector, 239 proc_ptr new_handler, 240 proc_ptr *old_handler 241 ) 242 { 243 _CPU_Fatal_halt( 0xdeaddead ); 244 } 245 246 /*PAGE 247 * 248 * _CPU_ISR_install_vector 154 249 * 155 250 * This kernel routine installs the RTEMS handler for the … … 182 277 /* 183 278 * We put the actual user ISR address in '_ISR_vector_table'. This will 184 * be used by the _ ISR_Handler so the user gets control.279 * be used by the _CPU_ISR_Handler so the user gets control. 185 280 */ 186 281 … … 216 311 void _CPU_Internal_threads_Idle_thread_body( void ) 217 312 { 218 while (1) 219 pause(); 220 } 313 while (1) 314 pause(); 315 } 316 317 /*PAGE 318 * 319 * _CPU_Context_Initialize 320 */ 221 321 222 322 void _CPU_Context_Initialize( … … 228 328 ) 229 329 { 230 unsigned32 *addr; 231 unsigned32 jmp_addr; 232 unsigned32 _stack_low; /* lowest "stack aligned" address */ 233 unsigned32 _stack_high; /* highest "stack aligned" address */ 234 unsigned32 _the_size; 235 236 jmp_addr = (unsigned32) _entry_point; 237 238 /* 239 * On CPUs with stacks which grow down, we build the stack 240 * based on the _stack_high address. On CPUs with stacks which 241 * grow up, we build the stack based on the _stack_low address. 242 */ 243 244 _stack_low = ((unsigned32)(_stack_base) + CPU_STACK_ALIGNMENT); 245 _stack_low &= ~(CPU_STACK_ALIGNMENT - 1); 246 247 _stack_high = ((unsigned32)(_stack_base) + _size); 248 _stack_high &= ~(CPU_STACK_ALIGNMENT - 1); 249 250 _the_size = _size & ~(CPU_STACK_ALIGNMENT - 1); 251 252 /* 253 * Slam our jmp_buf template into the context we are creating 254 */ 255 256 memcpy(_the_context, default_context, sizeof(jmp_buf)); 257 258 addr = (unsigned32 *)_the_context; 330 void *source; 331 unsigned32 *addr; 332 unsigned32 jmp_addr; 333 unsigned32 _stack_low; /* lowest "stack aligned" address */ 334 unsigned32 _stack_high; /* highest "stack aligned" address */ 335 unsigned32 _the_size; 336 337 jmp_addr = (unsigned32) _entry_point; 338 339 /* 340 * On CPUs with stacks which grow down, we build the stack 341 * based on the _stack_high address. On CPUs with stacks which 342 * grow up, we build the stack based on the _stack_low address. 343 */ 344 345 _stack_low = ((unsigned32)(_stack_base) + CPU_STACK_ALIGNMENT); 346 _stack_low &= ~(CPU_STACK_ALIGNMENT - 1); 347 348 _stack_high = ((unsigned32)(_stack_base) + _size); 349 _stack_high &= ~(CPU_STACK_ALIGNMENT - 1); 350 351 _the_size = _size & ~(CPU_STACK_ALIGNMENT - 1); 352 353 /* 354 * Slam our jmp_buf template into the context we are creating 355 */ 356 357 if ( _new_level == 0 ) 358 source = _CPU_Context_Default_with_ISRs_enabled.regs; 359 else 360 source = _CPU_Context_Default_with_ISRs_disabled.regs; 361 362 memcpy(_the_context, source, sizeof(jmp_buf)); 363 364 addr = (unsigned32 *)_the_context; 259 365 260 366 #if defined(hppa1_1) 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 367 *(addr + RP_OFF) = jmp_addr; 368 *(addr + SP_OFF) = (unsigned32)(_stack_low + CPU_FRAME_SIZE); 369 370 /* 371 * See if we are using shared libraries by checking 372 * bit 30 in 24 off of newp. If bit 30 is set then 373 * we are using shared libraries and the jump address 374 * is at what 24 off of newp points to so shove that 375 * into 24 off of newp instead. 376 */ 377 378 if (jmp_addr & 0x40000000) { 379 jmp_addr &= 0xfffffffc; 380 *(addr + RP_OFF) = (unsigned32)*(unsigned32 *)jmp_addr; 381 } 276 382 #elif defined(sparc) 277 383 278 279 280 281 282 283 284 285 286 287 384 /* 385 * See /usr/include/sys/stack.h in Solaris 2.3 for a nice 386 * diagram of the stack. 387 */ 388 389 asm ("ta 0x03"); /* flush registers */ 390 391 *(addr + RP_OFF) = jmp_addr + ADDR_ADJ_OFFSET; 392 *(addr + SP_OFF) = (unsigned32)(_stack_high - CPU_FRAME_SIZE); 393 *(addr + FP_OFF) = (unsigned32)(_stack_high); 288 394 #else 289 395 #error "UNKNOWN CPU!!!" 290 396 #endif 291 397 292 if (_new_level) 293 _CPU_ISR_Set_signal_level(1); 294 else 295 _CPU_ISR_Set_signal_level(0);296 297 } 398 } 399 400 /*PAGE 401 * 402 * _CPU_Context_restore 403 */ 298 404 299 405 void _CPU_Context_restore( … … 301 407 ) 302 408 { 303 longjmp(next->regs, 0); 304 } 409 sigprocmask( SIG_SETMASK, &next->isr_level, 0 ); 410 longjmp( next->regs, 0 ); 411 } 412 413 /*PAGE 414 * 415 * _CPU_Context_switch 416 */ 305 417 306 418 void _CPU_Context_switch( … … 309 421 ) 310 422 { 311 /* 312 * Save the current context 313 */ 314 315 if (setjmp(current->regs) == 0) { 316 317 /* 318 * Switch to the new context 319 */ 320 321 longjmp(next->regs, 0); 322 } 323 } 423 /* 424 * Switch levels in one operation 425 */ 426 427 sigprocmask( SIG_SETMASK, &next->isr_level, ¤t->isr_level ); 428 429 if (setjmp(current->regs) == 0) { /* Save the current context */ 430 longjmp(next->regs, 0); /* Switch to the new context */ 431 } 432 } 433 434 /*PAGE 435 * 436 * _CPU_Save_float_context 437 */ 324 438 325 439 void _CPU_Save_float_context( … … 329 443 } 330 444 445 /*PAGE 446 * 447 * _CPU_Restore_float_context 448 */ 449 331 450 void _CPU_Restore_float_context( 332 451 Context_Control_fp *fp_context … … 335 454 } 336 455 337 void _CPU_ISR_Set_signal_level(unsigned32 level) 338 { 339 if (level) 340 _CPU_Disable_signal(); 341 else 342 _CPU_Enable_signal(0); 343 } 344 345 346 unsigned32 _CPU_Disable_signal(void) 347 { 348 sigset_t old_mask; 349 sigset_t empty_mask; 350 351 sigemptyset(&empty_mask); 352 sigemptyset(&old_mask); 353 sigprocmask(SIG_BLOCK, &UNIX_SIGNAL_MASK, &old_mask); 354 355 if (memcmp((char *)&empty_mask, (char *)&old_mask, sizeof(sigset_t)) != 0) 356 return 1; 357 358 return 0; 359 } 360 361 362 void _CPU_Enable_signal(unsigned32 level) 363 { 364 if (level == 0) 365 sigprocmask(SIG_UNBLOCK, &UNIX_SIGNAL_MASK, 0); 366 } 367 368 369 /* 370 * Support for external and spurious interrupts on HPPA 371 * 372 * TODO: 373 * delete interrupt.c etc. 374 * Count interrupts 375 * make sure interrupts disabled properly 376 * should handler check again for more interrupts before exit? 377 * How to enable interrupts from an interrupt handler? 378 * Make sure there is an entry for everything in ISR_Vector_Table 379 */ 380 381 /* 382 * Init the external interrupt scheme 383 * called by bsp_start() 384 */ 385 386 rtems_status_code 387 signal_initialize(void) 388 { 389 struct sigaction act; 390 sigset_t mask; 391 392 /* mark them all active except for TraceTrap and Abort */ 393 394 sigfillset(&mask); 395 sigdelset(&mask, SIGTRAP); 396 sigdelset(&mask, SIGABRT); 397 sigdelset(&mask, SIGIOT); 398 sigdelset(&mask, SIGCONT); 399 sigprocmask(SIG_UNBLOCK, &mask, 0); 400 401 act.sa_handler = interrupt_handler; 402 act.sa_mask = mask; 403 #if defined(solaris) 404 act.sa_flags = SA_RESTART; 405 #else 406 act.sa_flags = 0; 407 #endif 408 409 sigaction(SIGHUP, &act, 0); 410 sigaction(SIGINT, &act, 0); 411 sigaction(SIGQUIT, &act, 0); 412 sigaction(SIGILL, &act, 0); 413 sigaction(SIGEMT, &act, 0); 414 sigaction(SIGFPE, &act, 0); 415 sigaction(SIGKILL, &act, 0); 416 sigaction(SIGBUS, &act, 0); 417 sigaction(SIGSEGV, &act, 0); 418 sigaction(SIGSYS, &act, 0); 419 sigaction(SIGPIPE, &act, 0); 420 sigaction(SIGALRM, &act, 0); 421 sigaction(SIGTERM, &act, 0); 422 sigaction(SIGUSR1, &act, 0); 423 sigaction(SIGUSR2, &act, 0); 424 sigaction(SIGCHLD, &act, 0); 425 sigaction(SIGCLD, &act, 0); 426 sigaction(SIGPWR, &act, 0); 427 sigaction(SIGVTALRM, &act, 0); 428 sigaction(SIGPROF, &act, 0); 429 sigaction(SIGIO, &act, 0); 430 sigaction(SIGWINCH, &act, 0); 431 sigaction(SIGSTOP, &act, 0); 432 sigaction(SIGTTIN, &act, 0); 433 sigaction(SIGTTOU, &act, 0); 434 sigaction(SIGURG, &act, 0); 435 /* 436 * XXX: Really should be on HPUX. 437 */ 438 439 #if defined(hppa1_1) 440 sigaction(SIGLOST, &act, 0); 441 #endif 442 443 return RTEMS_SUCCESSFUL; 444 } 445 446 447 /* 448 * External interrupt handler. 449 * This is installed as cpu interrupt handler. 450 * It vectors out to specific external interrupt handlers. 451 */ 452 453 void 454 interrupt_handler(int vector) 455 { 456 if (_ISR_Nest_level++ == 0) { 457 /* switch to interrupt stack */ 458 } 459 460 _Thread_Dispatch_disable_level++; 461 462 if (_ISR_Vector_table[vector]) { 463 _ISR_Vector_table[vector](vector); 464 } 465 else { 466 Stray_signal(vector); 467 } 468 469 if (_ISR_Nest_level-- == 0) { 470 /* switch back to original stack */ 471 } 472 473 _Thread_Dispatch_disable_level--; 474 475 if (_Thread_Dispatch_disable_level == 0 && 476 (_Context_Switch_necessary || _ISR_Signals_to_thread_executing)) { 477 _CPU_Enable_signal(0); 478 _Thread_Dispatch(); 479 } 480 } 481 482 483 void 484 Stray_signal(int sig_num) 485 { 486 char buffer[ 80 ]; 487 488 /* 489 * We avoid using the stdio section of the library. 490 * The following is generally safe. 491 */ 492 493 write( 494 2, 495 buffer, 496 sprintf( buffer, "Stray signal %d\n", sig_num ) 497 ); 456 /*PAGE 457 * 458 * _CPU_ISR_Disable_support 459 */ 460 461 unsigned32 _CPU_ISR_Disable_support(void) 462 { 463 sigset_t old_mask; 464 sigset_t empty_mask; 465 466 sigemptyset(&empty_mask); 467 sigemptyset(&old_mask); 468 sigprocmask(SIG_BLOCK, &_CPU_Signal_mask, &old_mask); 469 470 if (memcmp((char *)&empty_mask, (char *)&old_mask, sizeof(sigset_t)) != 0) 471 return 1; 472 473 return 0; 474 } 475 476 /*PAGE 477 * 478 * _CPU_ISR_Enable 479 */ 480 481 void _CPU_ISR_Enable( 482 unsigned32 level 483 ) 484 { 485 if (level == 0) 486 sigprocmask(SIG_UNBLOCK, &_CPU_Signal_mask, 0); 487 else 488 sigprocmask(SIG_BLOCK, &_CPU_Signal_mask, 0); 489 } 490 491 /*PAGE 492 * 493 * _CPU_ISR_Handler 494 * 495 * External interrupt handler. 496 * This is installed as a UNIX signal handler. 497 * It vectors out to specific user interrupt handlers. 498 */ 499 500 void _CPU_ISR_Handler(int vector) 501 { 502 extern void _Thread_Dispatch(void); 503 extern unsigned32 _Thread_Dispatch_disable_level; 504 extern boolean _Context_Switch_necessary; 505 506 507 if (_ISR_Nest_level++ == 0) { 508 /* switch to interrupt stack */ 509 } 510 511 _Thread_Dispatch_disable_level++; 512 513 if (_ISR_Vector_table[vector]) { 514 _ISR_Vector_table[vector](vector); 515 } else { 516 _CPU_Stray_signal(vector); 517 } 518 519 if (_ISR_Nest_level-- == 0) { 520 /* switch back to original stack */ 521 } 522 523 _Thread_Dispatch_disable_level--; 524 525 if (_Thread_Dispatch_disable_level == 0 && 526 (_Context_Switch_necessary || _ISR_Signals_to_thread_executing)) { 527 _CPU_ISR_Enable(0); 528 _Thread_Dispatch(); 529 } 530 } 531 532 /*PAGE 533 * 534 * _CPU_Stray_signal 535 */ 536 537 void _CPU_Stray_signal(int sig_num) 538 { 539 char buffer[ 80 ]; 540 541 /* 542 * We avoid using the stdio section of the library. 543 * The following is generally safe. 544 */ 545 546 write( 547 2, 548 buffer, 549 sprintf( buffer, "Stray signal %d\n", sig_num ) 550 ); 498 551 499 500 501 502 * we won't callStray_signal, so this is ok.503 552 /* 553 * If it was a "fatal" signal, then exit here 554 * If app code has installed a hander for one of these, then 555 * we won't call _CPU_Stray_signal, so this is ok. 556 */ 504 557 505 switch (sig_num) 506 { 507 case SIGINT: 508 case SIGHUP: 509 case SIGQUIT: 510 case SIGILL: 511 case SIGEMT: 512 case SIGKILL: 513 case SIGBUS: 514 case SIGSEGV: 515 case SIGTERM: 516 _CPU_Fatal_error(0x100 + sig_num); 517 } 518 } 519 520 521 void 522 _CPU_Fatal_error(unsigned32 error) 523 { 524 setitimer(ITIMER_REAL, 0, 0); 525 526 _exit(error); 527 } 528 529 int 530 _CPU_ffs(unsigned32 value) 531 { 532 int output; 533 534 output = ffs(value); 535 output = output - 1; 536 537 return(output); 538 } 558 switch (sig_num) { 559 case SIGINT: 560 case SIGHUP: 561 case SIGQUIT: 562 case SIGILL: 563 case SIGEMT: 564 case SIGKILL: 565 case SIGBUS: 566 case SIGSEGV: 567 case SIGTERM: 568 _CPU_Fatal_error(0x100 + sig_num); 569 } 570 } 571 572 /*PAGE 573 * 574 * _CPU_Fatal_error 575 */ 576 577 void _CPU_Fatal_error(unsigned32 error) 578 { 579 setitimer(ITIMER_REAL, 0, 0); 580 581 _exit(error); 582 } 583 584 /*PAGE 585 * 586 * _CPU_ffs 587 */ 588 589 int _CPU_ffs(unsigned32 value) 590 { 591 int output; 592 extern int ffs( int ); 593 594 output = ffs(value); 595 output = output - 1; 596 597 return output; 598 }
Note: See TracChangeset
for help on using the changeset viewer.