/* * Unlock given mutex. * Preemption must be disabled. */ static __inline__ void Mutex_Unlock_Imp(struct Mutex* mutex) { KASSERT(g_preemptionDisabled); /* Make sure mutex was actually acquired by this thread. */ KASSERT(IS_HELD(mutex)); /* Unlock the mutex. */ mutex->state = MUTEX_UNLOCKED; mutex->owner = 0; /* * If there are threads waiting to acquire the mutex, * wake one of them up. Note that it is legal to inspect * the queue with interrupts enabled because preemption * is disabled, and therefore we know that no thread can * concurrently add itself to the queue. */ if (!Is_Thread_Queue_Empty(&mutex->waitQueue)) { Disable_Interrupts(); Wake_Up_One(&mutex->waitQueue); Enable_Interrupts(); } }
void Spawner( unsigned long arg ) { const char *program = "/c/a.exe"; char *exeFileData = 0; ulong_t exeFileLength; struct Exe_Format exeFormat; /* * Load the executable file data, parse ELF headers, * and load code and data segments into user memory. */ if (lprogdebug) { Print("Reading %s...\n", program); } if (Read_Fully(program, (void**) &exeFileData, &exeFileLength) != 0) { Print("Read_Fully failed to read %s from disk\n", program); goto fail; } if (lprogdebug) { Print("Read_Fully OK\n"); } if (Parse_ELF_Executable(exeFileData, exeFileLength, &exeFormat) != 0) { Print("Parse_ELF_Executable failed\n"); goto fail; } if (lprogdebug) { Print("Parse_ELF_Executable OK\n"); } if (Spawn_Program(exeFileData, &exeFormat) != 0) { Print("Spawn_Program failed\n"); goto fail; } /* * User program has been loaded, so we can free the * executable file data now. */ Free(exeFileData); exeFileData = 0; /* If we arrived here, everything was fine and the program exited */ Print("Hi ! This is the third (and last) string\n"); Print("If you see this you're happy\n"); Exit(0); fail: /* We failed; release any allocated memory */ Disable_Interrupts(); Free(virtSpace); Enable_Interrupts(); }
/* * Create a new user context of given size */ static struct User_Context *Create_User_Context(ulong_t size) { struct User_Context *context; int index; /* Size must be a multiple of the page size */ size = Round_Up_To_Page(size); if (userDebug) Print("Size of user memory == %lu (%lx) (%lu pages)\n", size, size, size / PAGE_SIZE); /* Allocate memory for the user context */ Disable_Interrupts(); context = (struct User_Context *)Malloc(sizeof(*context)); if (context != 0) context->memory = Malloc(size); Enable_Interrupts(); if (context == 0 || context->memory == 0) goto fail; /* * Fill user memory with zeroes; * leaving it uninitialized is a potential security flaw */ memset(context->memory, '\0', size); context->size = size; /* Allocate an LDT descriptor for the user context */ context->ldtDescriptor = Allocate_Segment_Descriptor(); if (context->ldtDescriptor == 0) goto fail; if (userDebug) Print("Allocated descriptor %d for LDT\n", Get_Descriptor_Index(context->ldtDescriptor)); Init_LDT_Descriptor(context->ldtDescriptor, context->ldt, NUM_USER_LDT_ENTRIES); index = Get_Descriptor_Index(context->ldtDescriptor); context->ldtSelector = Selector(KERNEL_PRIVILEGE, true, index); /* Initialize code and data segments within the LDT */ Init_Code_Segment_Descriptor(&context->ldt[0], (ulong_t) context->memory, size / PAGE_SIZE, USER_PRIVILEGE); Init_Data_Segment_Descriptor(&context->ldt[1], (ulong_t) context->memory, size / PAGE_SIZE, USER_PRIVILEGE); context->csSelector = Selector(USER_PRIVILEGE, false, 0); context->dsSelector = Selector(USER_PRIVILEGE, false, 1); /* Nobody is using this user context yet */ context->refCount = 0; /* Initialize background flag */ context->backgrounded = 0; /* Initialize all semaphore flags to 0 */ int sem_ind; for (sem_ind = 0; sem_ind < MAX_SEM_SIZE; sem_ind++) { context->sem_flags[sem_ind] = 0; } /* Success! */ return context; fail: /* We failed; release any allocated memory */ Disable_Interrupts(); if (context != 0) { if (context->memory != 0) Free(context->memory); Free(context); } Enable_Interrupts(); return 0; }
/* * Atomically make a thread runnable. * Assumes interrupts are currently enabled. */ void Make_Runnable_Atomic(struct Kernel_Thread* kthread) { Disable_Interrupts(); Make_Runnable(kthread); Enable_Interrupts(); }
/* * This function performs any needed initialization before * a thread start function is executed. Currently we just use * it to enable interrupts (since Schedule() always activates * a thread with interrupts disabled). */ static void Launch_Thread(void) { Enable_Interrupts(); }
static int Floppy_Transfer(int direction, int driveNum, int blockNum, char *buf) { struct Floppy_Drive *drive = &s_driveTable[driveNum]; struct Floppy_Parameters *params = drive->params; int cylinder, head, sector; enum DMA_Direction dmaDirection = direction == FLOPPY_READ ? DMA_READ : DMA_WRITE; uchar_t command; uchar_t st0, st1, st2; int result = -1; KASSERT(driveNum == 0); /* FIXME */ KASSERT(direction == FLOPPY_READ || direction == FLOPPY_WRITE); KASSERT(params != 0); LBA_To_CHS(&s_driveTable[driveNum], blockNum, &cylinder, &head, §or); if (!Floppy_Seek(driveNum, cylinder, head)) return -1; Disable_Interrupts(); /* Set up DMA for transfer */ Setup_DMA(dmaDirection, FDC_DMA, s_transferBuf, SECTOR_SIZE); /* Turn the floppy motor on */ Start_Motor(driveNum); /* * According to The Undocumented PC, we should wait 8 millis * before attempting a read or write. */ Micro_Delay(8000); if (direction == FLOPPY_READ) command = FDC_COMMAND_READ_SECTOR | FDC_MFM | FDC_SKIP_DELETED; else command = FDC_COMMAND_WRITE_SECTOR | FDC_MFM; /* Issue the command */ Floppy_Out(command); Floppy_Out((head << 2) | (driveNum & 3)); Floppy_Out(cylinder); Floppy_Out(head); Floppy_Out(sector); Floppy_Out(params->sectorSizeCode); Floppy_Out(params->sectors); Floppy_Out(params->gapLengthCode); Floppy_Out(0xFF); /* DTL */ /* Controller will issue an interrupt when the command is complete */ Wait_For_Interrupt(); Debug("Floppy_Transfer: received interrupt!\n"); /* Read results */ st0 = Floppy_In(); st1 = Floppy_In(); st2 = Floppy_In(); Floppy_In(); /* cylinder */ Floppy_In(); /* head */ Floppy_In(); /* sector number */ Floppy_In(); /* sector size */ Stop_Motor(driveNum); if (FDC_ST0_IS_SUCCESS(st0)) { Debug("Floppy_Transfer: successful transfer!\n"); result = 0; } Enable_Interrupts(); /*STOP(); */ return result; }
/* * Write a block at the logical block number indicated. */ static int IDE_Write(int driveNum, int blockNum, char *buffer) { int i; int head; int sector; int cylinder; short *bufferW; int reEnable = 0; if (driveNum < 0 || driveNum > (numDrives - 1)) { return IDE_ERROR_BAD_DRIVE; } if (blockNum < 0 || blockNum >= IDE_getNumBlocks(driveNum)) { return IDE_ERROR_INVALID_BLOCK; } if (Interrupts_Enabled()) { Disable_Interrupts(); reEnable = 1; } /* now compute the head, cylinder, and sector */ sector = blockNum % drives[driveNum].num_SectorsPerTrack + 1; cylinder = blockNum / (drives[driveNum].num_Heads * drives[driveNum].num_SectorsPerTrack); head = (blockNum / drives[driveNum].num_SectorsPerTrack) % drives[driveNum].num_Heads; if (ideDebug) { Print("request to write block %d\n", blockNum); Print(" head %d\n", head); Print(" cylinder %d\n", cylinder); Print(" sector %d\n", sector); } Out_Byte(IDE_SECTOR_COUNT_REGISTER, 1); Out_Byte(IDE_SECTOR_NUMBER_REGISTER, sector); Out_Byte(IDE_CYLINDER_LOW_REGISTER, LOW_BYTE(cylinder)); Out_Byte(IDE_CYLINDER_HIGH_REGISTER, HIGH_BYTE(cylinder)); Out_Byte(IDE_DRIVE_HEAD_REGISTER, IDE_DRIVE(driveNum) | head); Out_Byte(IDE_COMMAND_REGISTER, IDE_COMMAND_WRITE_SECTORS); /* wait for the drive */ while (In_Byte(IDE_STATUS_REGISTER) & IDE_STATUS_DRIVE_BUSY); bufferW = (short *)buffer; for (i = 0; i < 256; i++) { Out_Word(IDE_DATA_REGISTER, bufferW[i]); } if (ideDebug) Print("About to wait for Write \n"); /* wait for the drive */ while (In_Byte(IDE_STATUS_REGISTER) & IDE_STATUS_DRIVE_BUSY); if (In_Byte(IDE_STATUS_REGISTER) & IDE_STATUS_DRIVE_ERROR) { Print("ERROR: Got Read %d\n", In_Byte(IDE_STATUS_REGISTER)); return IDE_ERROR_DRIVE_ERROR; } if (reEnable) Enable_Interrupts(); return IDE_ERROR_NO_ERROR; }
/* * Spawn a user process. * Params: * program - the full path of the program executable file * command - the command, including name of program and arguments * pThread - reference to Kernel_Thread pointer where a pointer to * the newly created user mode thread (process) should be * stored * Returns: * The process id (pid) of the new process, or an error code * if the process couldn't be created. Note that this function * should return ENOTFOUND if the reason for failure is that * the executable file doesn't exist. */ int Spawn(const char *program, const char *command, struct Kernel_Thread **pThread) { /* * Hints: * - Call Read_Fully() to load the entire executable into a memory buffer * - Call Parse_ELF_Executable() to verify that the executable is * valid, and to populate an Exe_Format data structure describing * how the executable should be loaded * - Call Load_User_Program() to create a User_Context with the loaded * program * - Call Start_User_Thread() with the new User_Context * * If all goes well, store the pointer to the new thread in * pThread and return 0. Otherwise, return an error code. */ //TODO("Spawn a process by reading an executable from a filesystem"); char *exeFileData = 0; ulong_t exeFileLength; struct Exe_Format exeFormat; struct User_Context * pUserContext = NULL; struct Kernel_Thread* pkthread; int rc; if (lprogdebug) { Print("Reading %s...\n", program); } if ( (rc = Read_Fully(program, (void**) &exeFileData, &exeFileLength)) != 0) { Print("Read_Fully failed to read %s from disk\n", program); goto fail; } if (lprogdebug) { Print("Read_Fully OK\n"); } if ((rc = Parse_ELF_Executable(exeFileData, exeFileLength, &exeFormat)) != 0) { Print("Parse_ELF_Executable failed\n"); goto fail; } if (lprogdebug) { Print("Parse_ELF_Executable OK\n"); } if ( (rc = Load_User_Program(exeFileData, exeFileLength, &exeFormat, command, &pUserContext)) != 0) { Print("Load_User_Program failed\n"); goto fail; } if ((pkthread = Start_User_Thread(pUserContext, false)) == NULL) //ERROR detached should be false { Print("Start_User_Thread Failed!\n"); rc = -1; goto fail; } /* * User program has been loaded, so we can free the * executable file data now. */ Free(exeFileData); exeFileData = 0; /* If we arrived here, everything was fine and the program exited */ //Print("If you see this you're happy\n"); *pThread = pkthread; if(pThread == NULL) Print("wrong!\n"); return pkthread->pid; // Exit(0); as this is not a thread, we don't exit but return. fail: /* We failed; release any allocated memory */ //if(Interrupts_Enabled()) Disable_Interrupts(); if(pUserContext != NULL && pUserContext->memory != NULL) Free(pUserContext->memory); Enable_Interrupts(); return rc; }