CS644 Timer Interrupts and setup for hw3

 

/* timetest1.c: show we can get old PC off stack in interrupt handler */

/* Note: stop its execution with reboot by ~r */

#include <stdio.h>

#include <timer.h>

#include <pic.h>

#include <cpu.h>

 

#define LINELEN 100

#define MILLION 1000000

extern const IntHandler irq0inthand; /* assembler envelope */

 

void set_timer_count(int count); /* local function, could be static */

int icount;             /* global for int handler use */

 

void main()

{

  int count;

  char buf[LINELEN];

  int i;

  count = 30000; /* specify a number here to avoid input */

  /* Note that too-small startcounts (under 100?) will cause problems */

  /* because the PIC is bombarded with too-frequent interrupts */

  /* printf("Enter startcount for timer (for example, 30000): "); */

  /* fgets(buf,LINELEN,CONSOLE); *//* fgets takes dev# in SA lib vs. fd on UNIX */

  /*  sscanf(buf, "%d" ,&count); */

 

  cli();                        /* disable ints while setting them up */

  printf("Setting IDT interrupt gate descriptor for irq 0 (int n = 0x20)\n");

  set_intr_gate(TIMER0_IRQ+IRQ_TO_INT_N_SHIFT, &irq0inthand);

  printf("Commanding PIC to interrupt CPU for irq 0 (TIMER0_IRQ)\n");

  pic_enable_irq(TIMER0_IRQ);

  printf("Commanding timer to generate pulse train using this count\n");

  set_timer_count(count);

  printf("Enabling interrupts in CPU\n");

  icount = 0;

  sti();

  for (i=0;i<MILLION;i++)       /* million loops of 100 passes on 400Mhz cpu: secs*/

    work0();                    /* (slowed down by printf in int handler) */

  printf("Shutting down\n");

  cli();

  printf("saw %d interrupts\n",icount);

  pic_disable_irq(TIMER0_IRQ);

  sti();

}

 

int work0() {

    int i, sum=0;

 

    for (i=0; i<100; i++)

        sum += i;

    return 0;

}

 

/* Set up timer to count down from given count, then pulse, repeatedly */

/* These output pulses follow wires to the PIC to provide timer interrupts */

/* count of 0 sets max count, 65536 = 2**16 */

void set_timer_count(int count)

{

  outpt(TIMER_CNTRL_PORT, TIMER0|TIMER_SET_ALL|TIMER_MODE_RATEGEN);

  outpt(TIMER0_COUNT_PORT,count&0xff); /* set LSB here */

  outpt(TIMER0_COUNT_PORT,count>>8); /* and MSB here */

}

 

/* for cs644, show that struct StackLayout works */

#define NREGS 5

typedef struct  {

    unsigned int regs[NREGS];  /* 5 regs pushed by irq0inthand */

    unsigned int pc;          /* the old PC we want */

    unsigned short code;      /* the interrupt code */

    unsigned short cs;        /* the old CS (code seg reg) */

    unsigned int eflags;      /* the old EFLAGS we want */

} StackLayout;

 

void irq0inthandc(StackLayout sm)

{

    pic_end_int();      /* notify PIC with EOI command that its part is done */

 

 

    /* old PC should be in idle loop, between main and set_timer_count */

    kprintf("old PC = %x (main = %x)\n", sm.pc, (int)main);

    /* show IF before interrupt and now-- */

    kprintf("old IF = %d\n", (sm.eflags >> 9)&1); /* will be 1 */

    kprintf("current IF = %d\n", (get_eflags() >> 9)&1); /* will be 0 */

    icount++;

}

 

====================================================================================

    irq0.s  (in $pclibsrc)  The assembly-language envelope around the C interrupt handler.

    The lines marked "**" are essential.  The others could be dropped in our simple

    environment, where the segment registers never change.

 

    # like linux SAVE_MOST and RESTORE_MOST macros in irq.h

    .text

    .globl _irq0inthand

    KERNEL_DS = 0x18

 

    _irq0inthand: cld       # D bit gets restored to old val by iret

            push %es        # in case user code changes data segments

            push %ds

            pushl %eax      # save C scratch regs **

            pushl %edx      # **

            pushl %ecx      # **

            movl $KERNEL_DS, %edx

            mov %dx, %ds    # make sure our data segs are in use now

            mov %dx, %es

            call _irq0inthandc  # call C interrupt handler **

            popl %ecx       # **

            popl %edx       # **

            popl %eax       # **

            pop %ds

            pop %es

            iret            # **