/* * Calibrate the delay loop. * This will initialize s_spinCountPerTick, which indicates * how many iterations of the loop are executed per timer tick. */ static void Calibrate_Delay(void) { Disable_Interrupts(); /* Install temporarily interrupt handler */ Install_IRQ(TIMER_IRQ, &Timer_Calibrate); Enable_IRQ(TIMER_IRQ); Enable_Interrupts(); /* Wait a few ticks */ while (g_numTicks < CALIBRATE_NUM_TICKS) ; /* * Execute the spin loop. * The temporary interrupt handler will overwrite the * loop counter when the next tick occurs. */ Spin(INT_MAX); Disable_Interrupts(); /* * Mask out the timer IRQ again, * since we will be installing a real timer interrupt handler. */ Disable_IRQ(TIMER_IRQ); Enable_Interrupts(); }
/* * If the given thread has a User_Context, * switch to its memory space. * * Params: * kthread - the thread that is about to execute * state - saved processor registers describing the state when * the thread was interrupted */ void Switch_To_User_Context(struct Kernel_Thread* kthread, struct Interrupt_State* state) { /* * Hint: Before executing in user mode, you will need to call * the Set_Kernel_Stack_Pointer() and Switch_To_Address_Space() * functions. */ //TODO("Switch to a new user address space, if necessary"); Set_Kernel_Stack_Pointer((ulong_t)((kthread->stackPage)+PAGE_SIZE)); // ERROR: only user thread need this function if(Interrupts_Enabled()) Disable_Interrupts(); if (kthread->userContext != 0) { //Print("SuC: %d ldt: %d\n", (int)(kthread->userContext), // (int))); //Set_Kernel_Stack_Pointer((ulong_t)(kthread->esp)); Switch_To_Address_Space(kthread->userContext); //Print("Switch to Address Space!\n"); //Print("jump to %d\n", (int)(kthread->userContext->entryAddr)); //Dump_Interrupt_State(state); //KASSERT(0); } Enable_Interrupts(); }
int P(int sid) { struct Semaphore* sema = (&s_semaphoreList)->head; struct Mutex* mutex; struct Condition* cond; //find sem by sid while (sema != 0) { if (sema->sid == sid) { mutex = &(sema->mutex); // important cond = &(sema->cond); Enable_Interrupts(); Mutex_Lock(mutex); while(sema->count <= 0) { Cond_Wait(cond, mutex); //Print("WAKE UP!"); } sema->count--; Mutex_Unlock(mutex); Disable_Interrupts(); return 0; } sema = Get_Next_In_Semaphore_List(sema); } return -1; }
/* * Wake up all threads waiting on the given condition. * The mutex guarding the condition should be held! */ void Cond_Broadcast(struct Condition* cond) { KASSERT(Interrupts_Enabled()); Disable_Interrupts(); /* prevent scheduling */ Wake_Up(&cond->waitQueue); Enable_Interrupts(); /* resume scheduling */ }
/* * Wait for given thread to die. * Interrupts must be enabled. * Returns the thread exit code. */ int Join(struct Kernel_Thread* kthread) { int exitCode; KASSERT(Interrupts_Enabled()); /* It is only legal for the owner to join */ KASSERT(kthread->owner == g_currentThread); Disable_Interrupts(); /* Wait for it to die */ while (kthread->alive) { Wait(&kthread->joinQueue); } /* Get thread exit code. */ exitCode = kthread->exitCode; /* Release our reference to the thread */ Detach_Thread(kthread); Enable_Interrupts(); return exitCode; }
/* * Flush filesystem buffers * Params: none * Returns: 0 if successful, error code (< 0) if unsuccessful */ static int Sys_Sync(struct Interrupt_State *state) { int rc; Enable_Interrupts(); rc = Sync(); Disable_Interrupts(); return rc; }
/* * Open a file. * Params: * state->ebx - address of user string containing path of file to open * state->ecx - length of path * state->edx - file mode flags * * Returns: a file descriptor (>= 0) if successful, * or an error code (< 0) if unsuccessful */ static int Sys_Open(struct Interrupt_State *state) { char path[VFS_MAX_PATH_LEN] = {'\0', }; struct File **pFile; int fd; int rc; struct File** fileList = g_currentThread->userContext->fileList; for(fd = 0; fd < USER_MAX_FILES; fd++){ if(fileList[fd] == NULL){ pFile = &fileList[fd]; break; } } if(fd == USER_MAX_FILES) { return -1; } Copy_From_User(path, state->ebx, state->ecx); Enable_Interrupts(); if((rc = Open(path, state->edx, pFile)) < 0){ fd = rc; } Disable_Interrupts(); return fd; //TODO("Open system call"); }
/* * Voluntarily give up the CPU to another thread. * Does nothing if no other threads are ready to run. */ void Yield(void) { Disable_Interrupts(); Make_Runnable(g_currentThread); Schedule(); Enable_Interrupts(); }
/* * Exit the current thread. * Calling this function initiates a context switch. */ void Exit(int exitCode) { struct Kernel_Thread* current = g_currentThread; if (Interrupts_Enabled()) Disable_Interrupts(); /* Thread is dead */ current->exitCode = exitCode; current->alive = false; /* Clean up any thread-local memory */ Tlocal_Exit(g_currentThread); /* Notify the thread's owner, if any */ Wake_Up(¤t->joinQueue); /* Remove the thread's implicit reference to itself. */ Detach_Thread(g_currentThread); /* * Schedule a new thread. * Since the old thread wasn't placed on any * thread queue, it won't get scheduled again. */ Schedule(); /* Shouldn't get here */ KASSERT(false); }
/* * Mount a filesystem. * Params: * state->ebx - contains a pointer to the Mount_Syscall_Args structure * which contains the block device name, mount prefix, * and filesystem type * * Returns: * 0 if successful, error code if unsuccessful */ static int Sys_Mount(struct Interrupt_State *state) { int rc = 0; struct VFS_Mount_Request *args = 0; /* Allocate space for VFS_Mount_Request struct. */ if ((args = (struct VFS_Mount_Request *)Malloc(sizeof(struct VFS_Mount_Request))) == 0) { rc = ENOMEM; goto done; } /* Copy the mount arguments structure from user space. */ if (!Copy_From_User(args, state->ebx, sizeof(struct VFS_Mount_Request))) { rc = EINVALID; goto done; } /* * Hint: use devname, prefix, and fstype from the args structure * and invoke the Mount() VFS function. You will need to check * to make sure they are correctly nul-terminated. */ /* TODO("Mount system call"); */ Enable_Interrupts(); // duped from schulman // Print("eee %s %s %s\n", args->devname, args->prefix, args->fstype); rc = Mount(args->devname, args->prefix, args->fstype); Disable_Interrupts(); // duped from schulman done: if (args != 0) Free(args); return rc; }
/* * Open a directory. * Params: * state->ebx - address of user string containing path of directory to open * state->ecx - length of path * * Returns: a file descriptor (>= 0) if successful, * or an error code (< 0) if unsuccessful */ static int Sys_OpenDirectory(struct Interrupt_State *state) { char path[VFS_MAX_PATH_LEN] = {'\0' }; struct File **pDir; /* important */ int fd; int rc; struct File** fileList = g_currentThread->userContext->fileList; for(fd = 0; fd < USER_MAX_FILES; fd++){ if(fileList[fd] == NULL){ pDir = &fileList[fd]; break; } } if(fd == USER_MAX_FILES) { return -1; } Copy_From_User(path, state->ebx, state->ecx); Enable_Interrupts(); //Print("Sys_OpenDirectory : %s\n", path); if((rc = Open_Directory(path, pDir)) < 0){ /* important */ fd = rc; } //Print("%d, fileList[fd] : %x\n", fd, fileList[fd]); Disable_Interrupts(); return fd; //TODO("Open directory system call"); }
/* * Open a directory. * Params: * state->ebx - address of user string containing path of directory to open * state->ecx - length of path * * Returns: a file descriptor (>= 0) if successful, * or an error code (< 0) if unsuccessful */ static int Sys_OpenDirectory(struct Interrupt_State *state) { char *path; struct File *file; int rc = 0; rc = get_path_from_registers(state->ebx, state->ecx, &path); if(rc != 0) { return rc; } rc = next_descriptor(); if(rc < 0) { return rc; } Enable_Interrupts(); // duped from schulman rc = Open_Directory(path, &file); Disable_Interrupts(); Free(path); if(rc >= 0) { return add_file_to_descriptor_table(file); } else { return rc; } }
/* * Read a directory entry from an open directory handle. * Params: * state->ebx - file descriptor of the directory * state->ecx - user address of struct VFS_Dir_Entry to copy entry into * Returns: 0 if successful, error code (< 0) if unsuccessful */ static int Sys_ReadEntry(struct Interrupt_State *state) { int bytes_written = 0; /* where is the file table? */ if(state->ebx > USER_MAX_FILES) { return EINVALID; } if( g_currentThread->userContext->file_descriptor_table[state->ebx] ) { void *data_buffer = Malloc(sizeof(struct VFS_Dir_Entry)); if(!data_buffer) { return ENOMEM; } Enable_Interrupts(); bytes_written = Read_Entry(g_currentThread->userContext->file_descriptor_table[state->ebx], data_buffer); Disable_Interrupts(); if(bytes_written < 0) { Free(data_buffer); return bytes_written; } if (!Copy_To_User(state->ecx, data_buffer, sizeof(struct VFS_Dir_Entry))) { Free(data_buffer); return EINVALID; } Free(data_buffer); return bytes_written; } else { return ENOTFOUND; } }
int V(int sid) { struct Semaphore* sema = (&s_semaphoreList)->head; struct Mutex* mutex; struct Condition* cond; //find sem by sid while (sema != 0) { if (sema->sid == sid) { mutex = &(sema->mutex); cond = &(sema->cond); Enable_Interrupts(); Mutex_Lock(mutex); sema->count = sema->count + 1; //Print("wait queue : %d", cond->waitQueue); Cond_Broadcast(cond); Mutex_Unlock(mutex); Disable_Interrupts(); return 0; } sema = Get_Next_In_Semaphore_List(sema); } return -1; }
/* * Exit system call. * The interrupted user process is terminated. * Params: * state->ebx - process exit code * Returns: * Never returns to user mode! */ static int Sys_Exit(struct Interrupt_State* state) { Enable_Interrupts(); Detach_User_Context(g_currentThread); Disable_Interrupts(); Exit(state->ebx); return 0; }
//------------------------------------------------------------------------------ // Main Function: //------------------------------------------------------------------------------ void main() { //-------------------------------------------------------------------------- // PIC Initialization Section //-------------------------------------------------------------------------- Disable_Interrupts(GLOBAL); // all interrupts OFF Setup_adc(ADC_OFF); // ADC not needed Setup_adc_ports(NO_ANALOGS); // No ADC ports needed Setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256); // Timer 0 set for 42.6us, Setup_timer_1(T1_DISABLED); // Timer 1 Set_Tris_A(TRISA_Enabled); // SPI Disabled Set_Tris_B(TRISB_Disable); // Flash SPI Disabled Set_Tris_C(TRISC_Disable); // Flash SPI Disabled Output_high(FLASH_SELECT); // Slash Select High Output_high(FLASH_CLOCK); // Pulse the clock Output_low(RTC_RST); // Disable RTC Output_High(FPGALoad); // FPGA Upload pin Output_High(FPGAReset); // FPGA reset off Output_High(TestLED); // indication of boot up spi_enabled = False; // ZBC to PIC SPI disabled initially spi_write = False; // ZBC to PIC SPI disabled initially Refresh_RTCSPI(); // Refresh data from RTC into SPI buffer //-------------------------------------------------------------------------- // USB Initialization Section //-------------------------------------------------------------------------- usb_init_cs(); // Initialize the USB Connection if(read_eeprom(BOOT_TYPE) > 0) { // We want boot from FLASH FlashToFPGA(); // If not hooked up to USB then try to init Output_Low(FPGAReset); // FPGA reset off Output_High(FPGAReset); // FPGA reset off Output_Low(TestLED); // Turn off Test LED } else { FGPA_SPI_Init(); // Put PIC in SPI Slave mode } //-------------------------------------------------------------------------- // Main Command Loop: //-------------------------------------------------------------------------- do { // Always do USB Task usb_task(); // so it will detect USB pluging in if(usb_enumerated()) { // Are we plugged into the USB port ? usb_rcvdata_task(); // If so, check for data } if(spi_enabled) { // if ZBC to PIC SPI enabled, then check if(SSP_HAS_DATA()) { Handle_SPI(); // Handle SPI request from ZBC } } // Otherwise... just } while(True); // Continue forever, what else can we do ? }
/* * Wait for a process to exit. * Params: * state->ebx - pid of process to wait for * Returns: the exit code of the process, * or error code (< 0) on error */ static int Sys_Wait(struct Interrupt_State* state) { int exitcode; Enable_Interrupts(); exitcode = Join(Lookup_Thread(state->ebx, 1)); // weak; Disable_Interrupts(); return exitcode; //TODO("Wait system call"); }
/* * Create directory * Params: * state->ebx - address of user string containing path of new directory * state->ecx - length of path * * Returns: 0 if successful, error code (< 0) if unsuccessful */ static int Sys_CreateDir(struct Interrupt_State *state) { char *path; int rc = get_path_from_registers(state->ebx, state->ecx, &path); if(rc) { return rc; } Enable_Interrupts(); // Print("creating %s\n", path); rc = Create_Directory(path); Disable_Interrupts(); return rc; }
/* * Delete a file. * Params: * state->ebx - address of user string containing path to delete * state->ecx - length of path * * Returns: 0 if successful, error code (< 0) if unsuccessful */ static int Sys_Delete(struct Interrupt_State *state) { char *path; int rc = get_path_from_registers(state->ebx, state->ecx, &path); if(rc) { return rc; } Enable_Interrupts(); // duped from schulman rc = Delete(path); Disable_Interrupts(); Free(path); return rc; }
/* * The reaper thread. Its job is to de-allocate memory * used by threads which have finished. */ static void Reaper(ulong_t arg) { struct Kernel_Thread *kthread; Disable_Interrupts(); while (true) { /* See if there are any threads needing disposal. */ if ((kthread = s_graveyardQueue.head) == 0) { /* Graveyard is empty, so wait for a thread to die. */ Wait(&s_reaperWaitQueue); } else { /* Make the graveyard queue empty. */ Clear_Thread_Queue(&s_graveyardQueue); /* * Now we can re-enable interrupts, since we * have removed all the threads needing disposal. */ Enable_Interrupts(); Yield(); /* allow other threads to run? */ /* Dispose of the dead threads. */ while (kthread != 0) { struct Kernel_Thread* next = Get_Next_In_Thread_Queue(kthread); #if 0 Print("Reaper: disposing of thread @ %x, stack @ %x\n", kthread, kthread->stackPage); #endif Destroy_Thread(kthread); kthread = next; } /* * Disable interrupts again, since we're going to * do another iteration. */ Disable_Interrupts(); } } }
void Initialize_RTC(void) { Install_Interrupt_Handler(IRQ8, RTC_Handler); // Install the handler Disable_Interrupts(); outb(0x70, 0x8B); // Select register B and disable NMI char prev = inb(0x71); // Read the current value of register B outb(0x70, 0x8B); outb(0x71, prev | 0x40);// Write the prev value, turning on bit 6 or register B Enable_Interrupts(); kprintf("Real Time Clock Initialized\n"); }
static int Sys_GetCwd(struct Interrupt_State *state) { char spath[VFS_MAX_PATH_LEN] = {'\0', }; int rc; Enable_Interrupts(); rc = Get_Path(Get_Cwd(), spath); Disable_Interrupts(); Copy_To_User(state->ebx, spath, state->ecx); return rc; }
/* * The mutex is currently locked. * Atomically reenable preemption and wait in the * mutex's wait queue. */ static void Mutex_Wait(struct Mutex *mutex) { KASSERT(mutex->state == MUTEX_LOCKED); KASSERT(g_preemptionDisabled); Disable_Interrupts(); g_preemptionDisabled = false; Wait(&mutex->waitQueue); g_preemptionDisabled = true; Enable_Interrupts(); }
/* * Wait for a process to exit. * Params: * state->ebx - pid of process to wait for * Returns: the exit code of the process, * or error code (< 0) on error */ static int Sys_Wait(struct Interrupt_State* state) { int exit_code; struct Kernel_Thread *kthread=Lookup_Thread((int)state->ebx); if(kthread==NULL)return -1; Enable_Interrupts(); exit_code = Join(kthread); Disable_Interrupts(); return exit_code; }
/* * Get file metadata. * Params: * state->ebx - address of user string containing path of file * state->ecx - length of path * state->edx - user address of struct VFS_File_Stat object to store metadata in * * Returns: 0 if successful, error code (< 0) if unsuccessful */ static int Sys_Stat(struct Interrupt_State *state) { char path[VFS_MAX_PATH_LEN] = {'\0', }; int rc = 0; Copy_From_User(path, state->ebx, state->ecx); Enable_Interrupts(); rc = Stat(path, (struct VFS_File_Stat *)(USER_BASE_ADDR + state->edx)); /* weak */ Disable_Interrupts(); return rc; //TODO("Stat system call"); }
/* * Wait for a process to exit. * Params: * state->ebx - pid of process to wait for * Returns: the exit code of the process, * or error code (< 0) on error */ static int Sys_Wait(struct Interrupt_State *state) { int exitCode; struct Kernel_Thread *kthread = Lookup_Thread(state->ebx, 0); if (kthread == 0) return -12; Enable_Interrupts(); exitCode = Join(kthread); Disable_Interrupts(); return exitCode; }
/* * Destroy a User_Context object, including all memory * and other resources allocated within it. */ void Destroy_User_Context(struct User_Context *userContext) { KASSERT(userContext->refCount == 0); /* Free the context's LDT descriptor */ Free_Segment_Descriptor(userContext->ldtDescriptor); /* Free the context's memory */ Disable_Interrupts(); Free(userContext->memory); Free(userContext); Enable_Interrupts(); }
/* * Wait for the controller to issue an interrupt. * Must be called with interrupts disabled. */ static void Wait_For_Interrupt(void) { KASSERT(!Interrupts_Enabled()); /* Spin wait */ s_interruptOccurred = 0; Enable_Interrupts(); while (!s_interruptOccurred) { /* FIXME: Could sleep here */ } Disable_Interrupts(); }
/* * Read a directory entry from an open directory handle. * Params: * state->ebx - file descriptor of the directory * state->ecx - user address of struct VFS_Dir_Entry to copy entry into * Returns: 0 if successful, error code (< 0) if unsuccessful */ static int Sys_ReadEntry(struct Interrupt_State *state) { int rc; struct File** fileList = g_currentThread->userContext->fileList; Enable_Interrupts(); //Print("%d, fileList[state->ebx] : %x\n", state->ebx, fileList[state->ebx]); rc = Read_Entry(fileList[state->ebx], (struct VFS_File_Stat *)(USER_BASE_ADDR + state->ecx)); /* weak */ Disable_Interrupts(); return rc; //TODO("ReadEntry system call"); }
/* * Create a new user process. * Params: * state->ebx - user address of name of executable * state->ecx - length of executable name * state->edx - user address of command string * state->esi - length of command string * Returns: pid of process if successful, error code (< 0) otherwise */ static int Sys_Spawn(struct Interrupt_State* state) { int retVal = -1; char *exeName = NULL; char *command = NULL; ulong_t exeNameLen = state->ecx + 1; /* +1 to add the 0 NULL later */ ulong_t commandLen = state->esi + 1; /* +1 to add the 0 NULL later */ struct Kernel_Thread* kthread = NULL; /* get some memory for the exe name and the args */ exeName = (char*) Malloc(exeNameLen); if (exeName == NULL) goto memfail; command = (char*) Malloc(commandLen); if (command == NULL) goto memfail; memset(exeName, '\0', exeNameLen); if(!Copy_From_User(exeName, state->ebx, exeNameLen)){ retVal = EUNSPECIFIED; goto fail; } memset(command, '\0', commandLen); if(!Copy_From_User(command, state->edx, commandLen)) { retVal = EUNSPECIFIED; goto fail; } Enable_Interrupts(); if ((retVal = Spawn(exeName, command, &kthread))) { goto fail; } Disable_Interrupts(); if (exeName!=NULL) Free(exeName); if (command!=NULL) Free(command); return kthread->pid; memfail: retVal = ENOMEM; fail: if(exeName) Free(exeName); if (command) Free(command); return retVal; }