Custom-OS-Kernel / phase2 / devinterrupt_handler.c
devinterrupt_handler.c
Raw
#include "../h/devinterrupt_handler.h"

extern pcb_t* currentProcess; // pointer to the current executing process
extern int processCount;
extern int device_semaphores[49]; // 49 device semaphores
extern int softBlockCount; // number of soft blocked processes
extern pcb_t* readyQueue; // tail pointer to the queue of ready pcbs
extern cpu_t startTime;
int interruptStartTime;

void InterruptHandler(unsigned int cause)
{
    STCK(interruptStartTime); //this is to record the time at which the interrupt happened

    // Extract bits 8 to 15 directly
    unsigned int ipField = (cause >> 8) & 0xFF;
    
    // Check if bit 0 is set; if so, call PANIC()
    if (ipField & (1 << 0)) {
        PANIC();
    } else {
        // Check bits 1 through 7 for active interrupts
        for (int i = 1; i < 8; i++) {
            if (ipField & (1 << i)) {
                InterruptLineHandler(i);
            }
        }
    }
}


void InterruptLineHandler(int line)
{
    if (line == 1) {
        // PLT timer
        currentProcess->p_time = currentProcess->p_time + (CURRENT_TOD - startTime); 
        currentProcess->p_s = *((state_t*) BIOSDATAPAGE);
        insertProcQ(&readyQueue, currentProcess);
        Scheduler();
    } else if (line == 2){
        // Interval time exception
        LDIT(100000);
        // Unblock all pcbs blocked on the pseudo-clock semaphore
        while (headBlocked(&device_semaphores[48]) != NULL) {
            pcb_t* unblockedPcb = removeBlocked(&device_semaphores[48]);
            if (unblockedPcb != NULL) {
                unblockedPcb->p_semAdd = NULL;
                unblockedPcb->p_time = (unblockedPcb->p_time) + (CURRENT_TOD - startTime);
                insertProcQ(&readyQueue, unblockedPcb);
                softBlockCount--;
            }
        } 

        device_semaphores[48] = 0; // reset the pseudo-clock semaphore to 0
        
        if (currentProcess == NULL) Scheduler();  /* passing control to the current process (if there is one) */
        else LDST((state_t *) 0x0FFFF000);

    } else {
        // Peripheral device interrupt
        memaddr* lineBitMapAddr = (memaddr*)(0x10000040 + ((line - 3)* 0x4));

        // For each bit that is set to 1, call NonTimerHandler
        for (int i = 0; i < 8; i++) {
            if ((*lineBitMapAddr) & (1 << i)) {
                NonTimerHandler(line, i);
            }
        }
    }
}


void NonTimerHandler(int line, int device)
{

    // Compute the address of the device register for the device that generated the interrupt
    devreg_t* deviceRegister = (devreg_t*) (0x10000054 + ((line - 3) * 0x80) + (device * 0x10));
    // Declare a pointer variable called termReg of type termreg_t to point to the computed address
    termreg_t* pointer = (termreg_t*) deviceRegister;
    unsigned int relDevStatus;
    int num;

    // Check if the terminal is a transmitter
    if (pointer->recv_status == 1) {
        relDevStatus = pointer->transm_status;
        pointer->transm_command = 1; // Acknowledge transmitter interrupt
        num = 0;
    } else {
        relDevStatus = pointer->recv_status;
        pointer->recv_command = 1; // Acknowledge receiver interrupt
        num = 1;
    }

    // Compute the index position for the device in the device_semaphores[] array
    int deviceNum = 2 * device + num;
    int index = (line - 3) * 8 + deviceNum;

    device_semaphores[index]++;
    pcb_t* removedPcb = removeBlocked(&device_semaphores[index]);
    if (removedPcb != NULL) {
        // process is successfully unblocked
        removedPcb->p_time = removedPcb->p_time + (CURRENT_TOD - interruptStartTime);
        removedPcb->p_s.reg_v0 = relDevStatus;
        removedPcb->p_semAdd = NULL;
        insertProcQ(&readyQueue, removedPcb);
        softBlockCount--;   
    }

    if (currentProcess == NULL) Scheduler();  /* passing control to the current process (if there is one) */
    else LDST((state_t *) 0x0FFFF000);
}