Beispiel #1
0
/*
 * 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();
    }
}
Beispiel #2
0
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();
}
Beispiel #3
0
/*
 * 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;
}
Beispiel #4
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();
}
Beispiel #5
0
/*
 * 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();
}
Beispiel #6
0
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, &sector);

    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;
}
Beispiel #7
0
/*
 * 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;
}
Beispiel #8
0
/*
 * 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;
}