void HalStartSerial() { int oflags; // Open the term for reading and writing. if( (serialInFd = open(SERIAL_INPUT_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0 ) { HalPanic("failed to open input fd", errno); } if( (serialOutFd = open(SERIAL_OUTPUT_DEVICE, O_WRONLY | O_NOCTTY | O_NONBLOCK) ) < 0 ) { HalPanic("failed to open output fd", errno); } //Get the term settings tcgetattr(serialInFd, &serialSettingsOld); // For now, lets reuse whatever terminal settings we were started with. serialSettings.c_cflag = serialSettingsOld.c_cflag; serialSettings.c_iflag = serialSettingsOld.c_iflag; serialSettings.c_oflag = serialSettingsOld.c_oflag; serialSettings.c_lflag = serialSettingsOld.c_lflag; serialSettings.c_cc[VEOF] = serialSettingsOld.c_cc[VEOF]; serialSettings.c_cc[VEOL] = serialSettingsOld.c_cc[VEOL]; serialSettings.c_cc[VEOL2] = serialSettingsOld.c_cc[VEOL2]; serialSettings.c_cc[VERASE] = serialSettingsOld.c_cc[VERASE]; serialSettings.c_cc[VWERASE] = serialSettingsOld.c_cc[VWERASE]; serialSettings.c_cc[VKILL] = serialSettingsOld.c_cc[VKILL]; serialSettings.c_cc[VREPRINT] = serialSettingsOld.c_cc[VREPRINT]; serialSettings.c_cc[VINTR] = serialSettingsOld.c_cc[VINTR]; serialSettings.c_cc[VQUIT] = serialSettingsOld.c_cc[VQUIT]; serialSettings.c_cc[VSUSP] = serialSettingsOld.c_cc[VSUSP]; serialSettings.c_cc[VDSUSP] = serialSettingsOld.c_cc[VDSUSP]; serialSettings.c_cc[VSTART] = serialSettingsOld.c_cc[VSTART]; serialSettings.c_cc[VSTOP] = serialSettingsOld.c_cc[VSTOP]; serialSettings.c_cc[VLNEXT] = serialSettingsOld.c_cc[VLNEXT]; serialSettings.c_cc[VDISCARD] = serialSettingsOld.c_cc[VDISCARD]; serialSettings.c_cc[VMIN] = serialSettingsOld.c_cc[VMIN]; serialSettings.c_cc[VTIME] = serialSettingsOld.c_cc[VTIME]; serialSettings.c_cc[VSTATUS] = serialSettingsOld.c_cc[VSTATUS]; serialSettings.c_ispeed = serialSettingsOld.c_ispeed; serialSettings.c_ospeed = serialSettingsOld.c_ospeed; tcflush(serialInFd, TCIFLUSH); tcsetattr(serialInFd,TCSANOW,&serialSettings); fcntl(serialInFd, F_SETOWN, getpid( )); oflags = fcntl(serialInFd, F_GETFL); fcntl(serialInFd, F_SETFL, oflags | FASYNC); fcntl(serialOutFd, F_SETOWN, getpid( )); oflags = fcntl(serialOutFd, F_GETFL); fcntl(serialOutFd, F_SETFL, oflags | FASYNC); }
void HalSerialWriteChar(char data) { int writelen = write(serialOutFd, &data, sizeof(char)); if( writelen > 0 ) { } else if(writelen == 0) { HalPanic("Wrote 0 to STDOUT\n", 0); } else { HalPanic("Failed to write to STDOUT", errno); } }
/* * sigaltstack will cause this function to be called on an alternate stack. * This allows us to bootstrap new threads. */ void HalStackTrampoline( int SignalNumber ) { int status; //Save stack startup state before releaseing the tempContext. STACK_INIT_ROUTINE * foo = halTempContext->Foo; void * arg = halTempContext->Arg; status = _setjmp( halTempContext->Registers ); if( status == 0 ) { //Because status was 0 we know that this is the creation of //the stack frame. We can use the locals to construct the frame. halTempContextProcessed = TRUE; halTempContext = NULL; return; } else { //If we get here, then someone has jumped into a newly created thread. //Test to make sure we are atomic ASSERT( HalIsIrqAtomic(IRQ_LEVEL_MAX) ); foo(arg); //Returning from a function which was invoked by siglongjmp is not //supported. Foo should never retrun. HalPanic("Tried to return from trampoline!"); return; } }
/* * All signals call this routine. * This routine then calls the appropriate ISR Handler. */ void HalIsrHandler( int SignalNumber ) { INDEX index; enum IRQ_LEVEL irq; #ifdef DEBUG HalUpdateIsrDebugInfo(); #endif //We dont know which irq is associated with SignalNumber, so lets find it. for(index = 0; index < IRQ_LEVEL_COUNT; index++) { if( HalIrqToSignal[index] == SignalNumber ) { //We found it, call the appropriate ISR. irq = index; HalIsrJumpTable[irq](); #ifdef DEBUG //We are about to return into an unknown frame. //I can't predict what the irq will be there. HalInvalidateIsrDebugInfo(); #endif return; } } HalPanic("Signal delivered for which no Irq was registered", SignalNumber); }
/* * sigaltstack will cause this fuction to be called on an alternate stack. * This allows us to bootstrap new threads. */ void HalStackTrampoline( int SignalNumber ) { int status; status = _setjmp( halTempContext->Registers ); if( status == 0 ) { //Because status was 0 we know that this is the creation of //the stack frame. We can use the locals to construct the frame. halTempContextProcessed = TRUE; halTempContext = NULL; return; } else { //If we get here, then someone has jumped into a newly created thread. //Test to make sure we are atomic ASSERT( HalIsIrqAtomic(IRQ_LEVEL_TIMER) ); StackInitRoutine(); //Returning from a function which was invoked by siglongjmp is not //supported. Foo should never retrun. HalPanic("Tried to return from StackInitRoutine!\n", 0 ); return; } }
/* * All signals call this routine. * This routine then calls the appropriate ISR Handler. */ void HalIsrHandler( int SignalNumber ) { enum IRQ_LEVEL irq = HalSignalToIrq[SignalNumber]; HAL_ISR_HANDLER * handler = HalSignalToHandler[SignalNumber]; ASSERT (SignalNumber >= 0 && SignalNumber < NSIG); if (handler == NULL) { HalPanic("Signal delivered for which no Irq was registered"); } ASSERT (handler != NULL); ASSERT (irq != IRQ_LEVEL_NONE); #ifdef DEBUG HalUpdateIsrDebugInfo(); #endif handler(irq); #ifdef DEBUG //We are about to return into an unknown frame. //I can't predict what the irq will be there. HalInvalidateIsrDebugInfo(); #endif }
BOOL HalSerialGetChar(char * out) { int readlen = read(serialInFd, out, sizeof(char)); if(readlen > 0) { return TRUE; } else if(readlen == 0) { //We are allowed to recieve zero bytes from the serial. return FALSE; } else { if(errno == EINTR) { return FALSE; //We are allowed to be interrupted by another signal. } else if(errno == EAGAIN) { return FALSE; } else if(errno == EWOULDBLOCK) { return FALSE; } else { HalPanic("Recieved error from STDIN!\n", errno ); return FALSE; } } }
void HalCreateStackFrame( struct MACHINE_CONTEXT * Context, void * stack, COUNT stackSize, STACK_INIT_ROUTINE foo, void * arg) { int status; char * cstack = stack; stack_t newStack; sigset_t oldSet; sigset_t trampolineMask; struct sigaction switchStackAction; ASSUME(sigemptyset( &oldSet ), 0); ASSUME(sigemptyset( &trampolineMask ), 0); ASSUME(sigaddset( &trampolineMask, HAL_ISR_TRAMPOLINE ), 0); Context->Foo = foo; Context->Arg = arg; //We are about to bootstrap the new thread. Because we have to modify global //state here, we must make sure no interrupts occur until after we are bootstrapped. //We do all of this under the nose of the Isr unit. sigprocmask(SIG_BLOCK, &HalIrqToSigaction[IRQ_LEVEL_MAX].sa_mask, &oldSet); //NOTE: We use the interrupt mask here, because we want to block all operations. switchStackAction.sa_handler = HalStackTrampoline; switchStackAction.sa_mask = HalIrqToSigaction[IRQ_LEVEL_MAX].sa_mask; switchStackAction.sa_flags = SA_ONSTACK; sigaction(HAL_ISR_TRAMPOLINE, &switchStackAction, NULL ); halTempContext = Context; halTempContextProcessed = FALSE; newStack.ss_sp = cstack; newStack.ss_size = stackSize; newStack.ss_flags = 0; status = sigaltstack( &newStack, NULL ); if (status != 0) { HalPanicErrno("Failed to turn on sigaltstack."); } status = raise( HAL_ISR_TRAMPOLINE ); if (status != 0) { HalPanicErrno("Failed raise stack bootstrap signal"); } //At this point we know that we can't be interrupted. //The trampoline signal has been triggered. //All signals are blocked. //We will unblock the Trampoine signal so it gets delivered. ASSUME(sigprocmask( SIG_UNBLOCK, &trampolineMask, NULL ), 0); //Make sure that the signal was delivered. if (!halTempContextProcessed) { HalPanic("Failed to bootstrap new stack via signal"); } //Now that trampoline has fired, we can get back to the thread with longjump. //Lets turn off sigaltstack. newStack.ss_flags = SS_DISABLE; status = sigaltstack( &newStack, NULL ); if (status != 0) { HalPanicErrno("Failed to turn off sigaltstack."); } //Now that we have bootstrapped the new thread, lets restore the old mask. ASSUME(sigprocmask(SIG_SETMASK, &oldSet, NULL), 0); }