Stack *_get_stack( void ) { Stack *stack; if( _deque(&g_free_stacks,(void **)&stack) != ERR_NONE ) { return( 0 ); } _memclr( (void *) stack, sizeof(Stack) ); return( stack ); }
void _init_stacks( void ) { int i; // first, put all stacks into the free pool // // NOTE: queues must have been initialized first! for( i = 0; i < N_PROCESSES; ++i ) { if( _free_stack(&g_stacks[i]) != ERR_NONE ) { _kpanic( "init stacks: enqueue failed" ); } } // set up the system stack _memclr( (void *)&g_system_stack, sizeof(Stack) ); g_system_esp = ((unsigned int *)(&g_system_stack + 1)) - 2; // announce that we have initialized the stack module c_puts( " stacks" ); }
context_t *_setup_stack( stack_t *stack, uint32_t entry ) { uint32_t *tmp; context_t *context; /* ** Set up the initial stack contents for a (new) user process. ** ** We reserve two longwords at the bottom of the stack as ** scratch space. Above that, we simulate a call to exit() by ** inserting an exit status value and a dummy return address; we ** then simulate a call from exit() to the user main routine by ** pushing the address of exit() as a "return address". Finally, ** above that we place an context_t area that is initialized with ** the standard initial register contents. ** ** The low end of the stack will contain these values: ** ** esp -> ? <- context save area ** ... <- context save area ** ? <- context save area ** exit <- return address for main() ** 0 <- dummy return address ** status <- code for exit() call ** filler ** filler <- last word in stack ** ** When this process is dispatched, the context restore ** code will pop all the saved context information off ** the stack, leaving the */ /* ** First, compute a pointer to the 3rd-to-last longword ** (where the exit code will go). */ tmp = (uint32_t *)(stack + 1) - 3; // Next, fill in the dummy return information *tmp-- = X_SUCCESS; // exit() parameter *tmp-- = 0; // dummy return address *tmp = (uint32_t) exit; // "return" into exit() /* ** Now, fill in the "saved" context information. Begin ** by computing a pointer to the context save area. */ context = (context_t *)tmp - 1; /* ** Clear the context area to ensure that the "saved" ** general registers all contain 0. */ _memclr( (void *) context, sizeof(context_t) ); /* ** Initialize all the registers that should be non-zero. ** First, the segment registers. */ context->cs = GDT_CODE; context->ss = GDT_STACK; context->ds = GDT_DATA; context->es = GDT_DATA; context->fs = GDT_DATA; context->gs = GDT_DATA; /* ** EIP must contain the entry point of the user routine; ** in essence, we're pretending that this is where we ** were executing when the interrupt arrived. */ context->eip = entry; // EFLAGS must be properly initialized context->eflags = DEFAULT_EFLAGS; // return the pointer to the new context return( context ); }
Context *_setup_stack( Stack *stack, unsigned int entry ) { Context *context; unsigned int *ptr; // start by clearing the stack _memclr( (void *)stack, sizeof(Stack) ); // // We need to set up the initial stack contents for a (new) // user process. // // We reserve a longword at the bottom of the stack for // some scratch space. Above this, we'll place a dummy // "return address" so that if the process ever returns // from its main routine it will "return" to the exit() // system call. Finally, above that we'll initialize a // context for the process to use when dispatched. // // find the location immediately after the stack ptr = (unsigned int *)(stack + 1); // back up two longwords' distance ptr -= 2; // assign the dummy return address *ptr = (unsigned int) exit; // figure out where the process context area should be context = ((Context *)ptr) - 1; // initialize all the register fields in the context // area that should contain something other than zero // // first, the segment register save areas // This function is used for two processes that run within the kernel, // so they use the kernel stack. But since they are processes, they still // need an LDT. context->ss = LDT_DSEG; context->ds = LDT_DSEG; context->es = LDT_DSEG; context->fs = LDT_DSEG; context->gs = LDT_DSEG; context->cs = LDT_CSEG; // next, the entry point for the process context->eip = (unsigned int) entry; // the initial EFLAGS settings context->eflags = DEFAULT_EFLAGS; // finally, the context pointer goes into the PCB // so that the context can be "restored" when this // process is eventually dispatched context->esp = (unsigned int) ptr; // return the context pointer return( context ); }
/* ** _init_sio ** ** Initialize the UART chip. */ void _init_sio( void ) { // // Initialize SIO variables. // _memclr( (void *) g_inbuffer, sizeof(g_inbuffer) ); g_inlast = g_innext = g_inbuffer; g_incount = 0; _memclr( (void *) g_outbuffer, sizeof(g_outbuffer) ); g_outlast = g_outnext = g_outbuffer; g_outcount = 0; g_sending = 0; // // Next, initialize the UART. // // Initialize the FIFOs // // this is a bizarre little sequence of operations __outb( UA4_FCR, 0x20 ); __outb( UA4_FCR, 0x00 ); // reset __outb( UA4_FCR, UA5_FCR_FIFO_EN ); // 0x01 __outb( UA4_FCR, UA5_FCR_FIFO_EN | UA5_FCR_RXSR ); // 0x03 __outb( UA4_FCR, UA5_FCR_FIFO_EN | UA5_FCR_RXSR | UA5_FCR_TXSR ); // 0x07 // disable interrupts __outb( UA4_IER, 0 ); // select bank 1 and set the data rate __outb( UA4_LCR, UA4_LCR_BANK1 ); __outb( UA4_LBGD_L, BAUD_LOW_BYTE( BAUD_9600 ) ); __outb( UA4_LBGD_H, BAUD_HIGH_BYTE( BAUD_9600 ) ); // Select bank 0, and at the same time set the LCR for our // data characteristics. __outb( UA4_LCR, UA4_LCR_BANK0 | UA4_LCR_BITS_8 | UA4_LCR_1_STOP_BIT | UA4_LCR_NO_PARITY ); // Set the ISEN bit to enable the interrupt request signal. __outb( UA4_MCR, UA4_MCR_ISEN | UA4_MCR_DTR | UA4_MCR_RTS ); // Install our ISR __install_isr( INT_VEC_SERIAL_PORT_1, _isr_sio ); // Enable device interrupts. __outb( UA4_IER, UA4_IER_TX_INT_ENABLE | UA4_IER_RX_INT_ENABLE ); // Report that we're done. c_puts( " sio" ); }