Example #1
0
void DoSpoon(UserContext *context) {
    // Get an available process id.                                                                                       
    int newPid = pidCount++;
    PCB *child = (PCB *)malloc(sizeof(PCB));

    // If for any reason we can't fork, return ERROR to calling process.                                                  
    if (!newPid || !child) {
        context->regs[0] = ERROR;
        return;
    }

    PCB_Init(child);
    child->id = newPid;
    child->parent = current_process;
    queuePush(child->parent->children, child);
    if (queueIsEmpty(child->parent->children))
        TracePrintf(3, "DoSpoon: parent queue empty.\n");


    child->status = RUNNING;

    // Return 0 to child and arm the child for execution.                                                                 
    child->user_context = *context;
    queuePush(ready_queue, child);
    queuePush(process_queue, child);
    KernelContextSwitch(SpoonKernel, current_process, child);

    // Return child's pid to parent and resume execution of the parent.                                                   
    if (current_process->id == newPid) {
        *context = current_process->user_context;
        context->regs[0] = 0;
    } else {
        context->regs[0] = newPid;
    }
}
Example #2
0
void LoadNextProc(UserContext *context, int block) {
    DelayPop();
    if (!queueIsEmpty(ready_queue)) {
        if (current_process)  {
            current_process->user_context = *context;
            if (block == NO_BLOCK) {
                queuePush(ready_queue, current_process);
            }
        }

        PCB *next = queuePop(ready_queue);
        TracePrintf(1, "LoadNextProc: Next Process Id: %d\n", next->id);
        if(next->id == 2) 
            TracePrintf(3, "LoadNextProc: PCB has %p child\n", next->parent->children->head);
        WriteRegister(REG_PTBR1, (unsigned int) &(next->cow.pageTable)); 
        WriteRegister(REG_TLB_FLUSH, TLB_FLUSH_1);


        KernelContextSwitch(MyKCS, current_process, next);
        TracePrintf(1, "LoadNextProc: Got past MyKCS\n");
        *context = current_process->user_context;

        TracePrintf(3, "LoadNextProc: current user context pc is %p\n", context->pc);
    }
}
Example #3
0
// Begin executing the specified proc.
// NOTE: place the current proc into the correct queue before calling
void SwitchToProc(PCB *next_proc, UserContext *user_context) {
    TracePrintf(TRACE_LEVEL_FUNCTION_INFO, ">>> SwitchToProc()\n");
    assert(user_context);
    assert(next_proc);

    // Save current user state
    current_proc->user_context = *user_context;

    TracePrintf(TRACE_LEVEL_DETAIL_INFO, "Loading next proc context into %p\n", user_context);
    TracePrintf(TRACE_LEVEL_DETAIL_INFO, "Loading next proc PID: %d\n", next_proc->pid);
    *user_context = next_proc->user_context;
    // Set the TLB registers for the region 1 page table.
    WriteRegister(REG_PTBR1, (unsigned int) next_proc->region_1_page_table);
    WriteRegister(REG_TLB_FLUSH, TLB_FLUSH_1);

    PCB *old_proc = current_proc;
    current_proc = next_proc;
    int rc = KernelContextSwitch(&SaveKernelContextAndSwitch, old_proc, next_proc);
    if (SUCCESS == rc) {
        TracePrintf(TRACE_LEVEL_DETAIL_INFO, "Succesfully switched kernel context!\n");
    } else {
        TracePrintf(TRACE_LEVEL_NON_TERMINAL_PROBLEM, "Failed to save kernel context!\n");
        char *err_str = calloc(TERMINAL_MAX_LINE, sizeof(char));
        sprintf(err_str, "KernelContextSwitch failed!!! HALTING!!!\n", current_proc->pid);
        KernelTtyWriteInternal(0, err_str, strnlen(err_str, TERMINAL_MAX_LINE), user_context);
        free(err_str);
        Halt();
    }

    // Restore user state of new current process
    *user_context = current_proc->user_context;

    TracePrintf(TRACE_LEVEL_FUNCTION_INFO, "<<< SwitchToProc()\n");
}
Example #4
0
/* Wrapper of kernel context switch
 *
 * @param next_proc: the process to be switched in
 * @param user_context: current user context
 */
void context_switch_to(pcb_t *next_proc, UserContext *user_context) {
    int rc = 0;
    rc = KernelContextSwitch(&kernel_context_switch, running_proc, next_proc);
    if(rc) {
        log_err("Failed to execute magic function!");
        Halt();
    }
}
Example #5
0
/* Used for special processes that is not forked to init kernel context,
 * meaning this process is manually created by Yalnix
 */
void init_process_kernel(pcb_t *proc) {
    int rc = 0;
    
    rc = KernelContextSwitch(&init_newbie_kernel, proc, proc);
    if(rc) {
        log_err("Failed to execute magic function!");
        Halt();
    }
    //log_info("Init PID(%d) kernel stack done", proc->pid);
}
Example #6
0
void KernelStart(char *cmd_args[], unsigned int pmem_size, UserContext *uctxt) {
	//mark the initial KernelBrk
	KernelBrk = KernelDataEnd;

	//FreeFrameCount is only used page_table.c
	FreeFrameCount = pmem_size / PAGESIZE;

	ipc_table = (ObjectNode **) malloc(sizeof(ObjectNode *) * HASH_LEN);
	if (NULL == ipc_table) {
		TracePrintf(0, "ipc_table cannot be initialized!\n");
		return;
	}
	memset(ipc_table, 0, sizeof(ObjectNode *) * HASH_LEN);

	ReadyQueue	= (Queue *) malloc(sizeof(Queue));
	DelayQueue	= (Queue *) malloc(sizeof(Queue));
	if (NULL == ReadyQueue) {
		TracePrintf(0, "ReadyQueue cannot be initialized!\n");
		return;
	}
	if (NULL == DelayQueue) {
		TracePrintf(0, "DelayQueue cannot be initialized!\n");
		return;
	}

	memset(ReadyQueue,	0, sizeof(Queue));
	memset(DelayQueue,	0, sizeof(Queue));

	u_int i;
	for (i = 0; i < NUM_TERMINALS; i++) {
		BufferQueue[i]		= (Queue *) malloc(sizeof(Queue));
		ReceiveQueue[i]		= (Queue *) malloc(sizeof(Queue));
		TransmitQueue[i]	= (Queue *) malloc(sizeof(Queue));
		if (NULL == BufferQueue[i]) {
			TracePrintf(0, "BufferQueue[%d] cannot be initialized!\n", i);
			return;
		}
		if (NULL == ReceiveQueue[i]) {
			TracePrintf(0, "ReceiveQueue[%d] cannot be initialized!\n", i);
			return;
		}
		if (NULL == TransmitQueue[i]) {
			TracePrintf(0, "TransmitQueue[%d] cannot be initialized!\n", i);
			return;
		}


		memset(BufferQueue[i], 0, sizeof(Queue));
		memset(ReceiveQueue[i], 0, sizeof(Queue));
		memset(TransmitQueue[i], 0, sizeof(Queue));
	}

	//create interrupt vector table in kernel
	void **interruptVectorTable =
			 (void **) malloc(sizeof(void *) * TRAP_VECTOR_SIZE);
	if (NULL == interruptVectorTable) {
		TracePrintf(0, "Interrupt Vector Table cannot be initialized!\n");
		return;
	}

	//fill each entry in table with pointer to correct handler
	interruptVectorTable[TRAP_KERNEL] 	= &TrapKernelHandler;
	interruptVectorTable[TRAP_CLOCK] 	= &TrapClockHandler;
	interruptVectorTable[TRAP_ILLEGAL] 	= &TrapIllegalHandler;
	interruptVectorTable[TRAP_MEMORY] 	= &TrapMemoryHandler;
	interruptVectorTable[TRAP_MATH] 	= &TrapMathHandler;
	interruptVectorTable[TRAP_TTY_RECEIVE] 	= &TrapTtyReceiveHandler;
	interruptVectorTable[TRAP_TTY_TRANSMIT]	= &TrapTtyTransmitHandler;
	interruptVectorTable[TRAP_DISK] 	= &TrapDiskHandler;
	for (i = 8; i < 16; i++) {
		interruptVectorTable[i] 	= &TrapErrorHandler;
	}	

	//point REG_VECTOR_BASE to interrupt vector table
	WriteRegister(REG_VECTOR_BASE, (u_int) interruptVectorTable);
	TracePrintf(0, "Interrupt vector table initialization completed.\n");

	//Build page table for Region 0
	KernelPageTable = (PTE *) malloc(sizeof(PTE) * MAX_PT_LEN);
	if (NULL == KernelPageTable) {
		TracePrintf(0, "KernelPageTable cannot be initialized!\n");
		return;
	}
	memset(KernelPageTable, 0, sizeof(PTE) * MAX_PT_LEN);

	TracePrintf(0, "Page tables built successfully.\n");

	//create kernel stack union
	KS = (KernelStack *) KERNEL_STACK_BASE;
	TracePrintf(0, "Kernel stack initialization completed.\n");

	//build input init process PCB
	KS->CurrentPCB = InitPCB = InitializePCB();
	if (NULL == InitPCB) {
		TracePrintf(0, "InitPCB cannot be initialized!\n");
		return;
	}

	// We enablePTE after using all the malloc in the kernel because
	// only in this way we can make sure the getFreeFrame will be called
	// and update the FreeFrameCount.
	enablePTE(0, Page(KernelDataStart), PROT_READ | PROT_EXEC);
	enablePTE(Page(KernelDataStart), Page(KernelBrk), PROT_READ | PROT_WRITE);
	enablePTE(INTERFACE, Page(KERNEL_STACK_LIMIT), PROT_READ | PROT_WRITE);

	// initialize virtual memory registers
	WriteRegister(REG_PTBR0, (u_int) KernelPageTable);
	WriteRegister(REG_PTLR0, MAX_PT_LEN);
	WriteRegister(REG_PTBR1, (u_int) KS->CurrentPCB->pagetable);
	WriteRegister(REG_PTLR1, MAX_PT_LEN);
	TracePrintf(0, "Table information loading to hardware completed.\n");

	//set up the link list to keep track of free frames
	//from KernelBrk to KERNEL_STACK_BASE
	*FrameNumber(INTERFACE) = Page(KernelBrk);
	for (i = Page(KernelBrk); i < INTERFACE - 1; i++) {
		*FrameNumber(i) = i + 1;
	}
	*FrameNumber(INTERFACE - 1) = Page(VMEM_0_LIMIT);
	for (i = Page(VMEM_0_LIMIT); i < Page(pmem_size - 1); i++) {
		*FrameNumber(i) = i + 1;
	}
	TracePrintf(0, "Free frames' linked list has been set up.\n");

	//enable virtual memory
	WriteRegister(REG_VM_ENABLE, 1);
	VM_ENABLED = 1;
	TracePrintf(0, "Virtual memory has been enabled.\n");

	TracePrintf(0, "Load input program. (Default init)\n");
	if (NULL != cmd_args[0]) {
		if (FAILURE == LoadProgram(cmd_args[0], cmd_args, InitPCB)) {
			TracePrintf(0, "Load input program failed!\n");
			return;
		}
	} else {
		char *args[] = {"init", NULL};
		if (FAILURE == LoadProgram(args[0], args, InitPCB)) {
			TracePrintf(0, "Load input program failed!\n");
			return;
		}
	}

	TracePrintf(0, "Build the Idle process.\n");
	//build kernel idle process PCB
	IdlePCB = InitializePCB();
	if (NULL == IdlePCB) {
		TracePrintf(0, "IdlePCB cannot be initialized!\n");
		return;
	}

	//sp = virtual address of top of stack
	IdlePCB->uctxt.sp  = (void *) (VMEM_1_LIMIT
				     - INITIAL_STACK_FRAME_SIZE
				     - POST_ARGV_NULL_SPACE);
	//pc = virtual address of DoIdle function
	IdlePCB->uctxt.pc  = &DoIdle;

	//enable user stack for idle process	
	IdlePCB->pagetable[MAX_PT_LEN - 1].valid = 1;
	IdlePCB->pagetable[MAX_PT_LEN - 1].prot = PROT_READ | PROT_WRITE;

	if (0 == FreeFrameCount) {
		TracePrintf(0, "No frame for Idle process pagetable!\n");
		return;
	}

	IdlePCB->pagetable[MAX_PT_LEN - 1].pfn = getFreeFrame(0);

	//use MyKCS initialize IdlePCB's KC and KS
	KernelContextSwitch(KCKSInit, (void *) IdlePCB, NULL);
	TracePrintf(0, "How many time will this line be printed?\n");

	//copy current context into hardware provided context
	*uctxt = KS->CurrentPCB->uctxt;

	TracePrintf(0, "KernelStart finished.\n");
}