Page 1 of 1

Interrupt Vector Table Question

Posted: Tue Jul 20, 2004 2:17 am
by chen17981
Hi everyone:

There is no problem for me to use interrupt in real mode via IVT. But in pmode when i finish setting IDT, I do not know how to re-use the interrupt like in real mode. Maybe it has some relations with interrupt handle set in interrupt descriptor.

Could anyone give me some advise?

Re:Interrupt Vector Table Question

Posted: Tue Jul 20, 2004 3:36 am
by Pype.Clicker
you will *not* be able to use interrupts "like in real mode". Especially, you'll have to forget the whole idea of calling INT 10h for video setting or INT 13h for disk operations.

All you can do is define your own new INTs *and* define handlers for processor exceptions and hardware interrupts.

Re:Interrupt Vector Table Question

Posted: Tue Jul 20, 2004 7:39 am
by chen17981
Thank you for your help, Pype.Clicker

Sure, I know that in pmode i cannot use INT in realmode, and i should define ints, but i do not know how to define the new ints which could have the same function like ints in realmode.

And i still want to know that in pmode where the interrupt vector table is?

Could anyone help me? Thanks in advance.

Re:Interrupt Vector Table Question

Posted: Tue Jul 20, 2004 8:43 am
by Pype.Clicker
And i still want to know that in pmode where the interrupt vector table is?
It is where you tell it to be. The role of the IDTR register is to keep track for the CPU of where in linear address space *you* decided to store your IDT

Code: Select all

myIdt: resd 512 ; 256 ints * 8 bytes/descriptor

IDTR: dw 256*8-1
         dd myIdt

setup:
        mov eax, base_address_of_your_code
        add [IDTR+2],eax
        lidt [IDTR]
will make the array myIdt[] your pmode interrupt table ...
how to define the new ints which could have the same function
I need you to be more precise on what you want to achieve. There's no general answer except "use V8086 mode" ...

For instance, if all you want to do is receive IRQ1 when a key is pressed, you need to
- remap the PIC to avoid conflict with exceptions (http://www.osdev.org/osfaq2/index.php/C ... e%20PIC%3F)
- write a InterruptHandler for IRQ1 (for instance int 0x21 if you remapped IRQs starting at 0x20 like everybody around) -- see http://www.osdev.org/osfaq2/index.php/I ... ceRoutines
- read port 0x60 and send 0x20 on port 0x20 in that handler.

If you wish to have something more like RealMode INT16h (e.g. wait until a character is pressed and then return its ASCII code), sorry but you'll have to do everything yourself from the value you read out of port 0x60.

Same kind of situation occurs for reading from floppy, hard disk, setting video mode, etc.

There should be more infos about how to set up an int handler in BonaFide tutorials...

HTH

Re:Interrupt Vector Table Question

Posted: Wed Jul 21, 2004 2:15 am
by chen17981
Hi Pype.Clicker, please forgive me my stupid mind, I think my expression is unclear.

Everyone knows that In real mode, the first 1,024 bytes of memory of the computer are used as the interrupt handler table. This table has a 4 byte far address to the interrupt handler (Interrupt Service Routine - ISR) for each of the 256 interrupts.

So my question is that when I enter to PMode, if I store this interrupt handler table in my IDT, could i use these ints like in realmode, for example if I want to read a sector from a floppy,
what should I do in Pmode, I think it is very easy in realmode with using int 0x13.

Thank you in advance.

Re:Interrupt Vector Table Question

Posted: Wed Jul 21, 2004 10:34 am
by bkilgore
No, unfortunately you can't do this. All of those interrupt handlers were designed for real mode, so you would have to run it inside v8086 which is a lot of work to write (apparently, i haven't even tried yet).

If you want to read a sector from a floppy, you have to go through and write all the code to do it yourself, reading and writing bytes to the floppy controller ports. There should be some tutorials around here on how to interface with the floppy controller, and then there is always the intel floppy controller datasheet.

And you will have to do the same thing for dealing with the keyboard, mouse, and anything else that you would want to interface with.

Re:Interrupt Vector Table Question

Posted: Wed Jul 21, 2004 1:05 pm
by ASHLEY4
Its hard when your a beginner, so here go's

Code: Select all

idtr:   dw idt_end - idt - 1             ; IDT limit
   dd idt

include 'idt.asm'   
That leads to this

Code: Select all

idt:

;0 interrupt 0h
   dw div_error      ; div error
   dw sys_code
   db 0
   db sys_interrupt
   dw 0

;1 interrupt 1h
   dw debug_exception   ; debug exception
   dw sys_code
   db 0
   db sys_interrupt
   dw 0

;2 interrupt 2h
   dw nmi_interrupt   ; non maskable interrupt
   dw sys_code
   db 0
   db sys_interrupt
   dw 0

;3 interrupt 3h
   dw int3_trap      ; int3 trap
   dw sys_code
   db 0
   db sys_interrupt
   dw 0

;fill this with all the numbers

;253 interrupt FDh
   dw unhandled_int   ; reserved
   dw sys_code
   db 0
   db sys_interrupt
   dw 0

;254 interrupt FEh
   dw unhandled_int   ; reserved
   dw sys_code
   db 0
   db sys_interrupt
   dw 0

;255 interrupt FFh
   dw unhandled_int   ; reserved
   dw sys_code
   db 0
   db sys_interrupt
   dw 0
idt_end:
And these lead to this

Code: Select all

unhandled_int:
        pushad
        mov ax,8h
   mov es,ax
   mov byte [es:0xB809E], "U"
        popad
   iret

nmi_interrupt:
        pushad
        mov ax,8h
   mov es,ax
   mov byte [es:0xB809E], "N"
reboot1:
   jmp reboot1
        popad
        iret
clock_tick:
        pushad

        mov ax,8h
   mov es,ax
   ;mov esi, stringZ
   ;call print_string
   mov byte [es:0xB809E], "C"
   call irq_clear

        popad
   iret

keyboard_irq:
        pushad
        ;mov ax,8h
   ;mov es,ax
   ;mov byte [es:0xB809C], "K"
   call key_board
        popad
   iret

page_fault:
        pushad
        mov ax,8h
   mov es,ax
   mov byte [es:0xB809C], "P"
        popad
   iret

div_error:
        pushad
        mov ax,8h
   mov es,ax
   mov byte [es:0xB809C], "D"
        popad
   iret

put as many as you want here

irq_clear:
   push eax
   mov al, 0x20
   out 0x20, al      ; quiet screaming irq chip.
   pop eax
   ret
if you want more help ask

Re:Interrupt Vector Table Question

Posted: Wed Jul 21, 2004 4:44 pm
by Dreamsmith
bkilgore wrote:No, unfortunately you can't do this. All of those interrupt handlers were designed for real mode, so you would have to run it inside v8086 which is a lot of work to write (apparently, i haven't even tried yet).
Actually, I found it was a lot easier to write than I was expecting. I'm tempted to just cut and paste mine here. In fact...

Code: Select all

static inline void v86push16(UInt16 x)
{
   v86.tss.esp = (UInt16)(v86.tss.esp - 2);
   *(UInt16*)(v86.tss.ss * 16 + v86.tss.esp) = x;
}

static inline void v86push32(UInt32 x)
{
   v86.tss.esp = (UInt16)(v86.tss.esp - 4);
   *(UInt32*)(v86.tss.ss * 16 + v86.tss.esp) = x;
}

static inline UInt16 v86pop16(void)
{
   UInt16 result = *(UInt16*)(v86.tss.ss * 16 + v86.tss.esp);
   v86.tss.esp = (UInt16)(v86.tss.esp + 2);
   return result;
}

static inline UInt32 v86pop32(void)
{
   UInt32 result = *(UInt32*)(v86.tss.ss * 16 + v86.tss.esp);
   v86.tss.esp = (UInt16)(v86.tss.esp + 4);
   return result;
}

void callV86(UInt16 segment, UInt16 offset)
{
   int o32 = 0, a32 = 0;
   UInt32 err;

   v86.tss.cs = segment;
   v86.tss.eip = offset;
   v86.tss.eflags = (v86.tss.eflags & EFLAGS_REAL) | EFLAGS_VM;

   disablePreemption(currentTask); // disallow multitasking for the moment

   setTaskHandler(0x0D, currentTask->selector, 0); // this task is GPF handler

   ljmp(v86selector); // switch to V86 task
   err = pop();       // pop GPF error code

   for (;;)
   {
      UInt8 *ip = (UInt8*)(v86.tss.cs * 16 + v86.tss.eip);
      switch ( *ip )
      {
       case 0x66: // O32
         o32 = 1;
         v86.tss.eip = (UInt16)(v86.tss.eip + 1);
         continue;

       case 0x67: // A32
         a32 = 1;
         v86.tss.eip = (UInt16)(v86.tss.eip + 1);
         continue;

       case 0x9C: // PUSHF
         if ( o32 )
            v86push32(v86.tss.eflags);
         else
            v86push16(v86.tss.eflags);
         v86.tss.eip = (UInt16)(v86.tss.eip + 1);
         break;

       case 0x9D: // POPF
         if ( o32 )
            v86.tss.eflags = (v86pop32() & EFLAGS_REAL) | EFLAGS_VM;
         else
            v86.tss.eflags = (v86pop16() & EFLAGS_REAL) | EFLAGS_VM;
         v86.tss.eip = (UInt16)(v86.tss.eip + 1);
         break;

       case 0xCC: // INT 3
       case 0xCD: // INT x
         v86push16(v86.tss.eflags);
         v86push16(v86.tss.cs);
         v86push16(v86.tss.eip + (ip[0] - 0xCB));
         v86.tss.eip = *(UInt16*)(ip[0] == 0xCC ? 12 : ip[1] * 4);
         v86.tss.cs  = *(UInt16*)(ip[0] == 0xCC ? 14 : ip[1] * 4 + 2);
         v86.tss.eflags &= ~(EFLAGS_IF | EFLAGS_TF);
         break;

       case 0xCF: // IRET
         v86.tss.eip    = v86pop16();
         v86.tss.cs     = v86pop16();
         v86.tss.eflags = (v86pop16() & EFLAGS_REAL) | EFLAGS_VM;
         break;

       default:
         kprintf("V86 unknown opcode: %02X (err=%04X)\n", *ip, (UInt16)err);
         dumpTSS(&v86.tss);
         // The ability in C to fall through into the next case is an
         // outstanding feature of the language, not a design flaw.

       case 0xF4: // HLT
         setEFLAGS(getEFLAGS() & ~EFLAGS_NT); // clear Nested Task flag
         resetTaskSelector(v86selector);      // clear busy bit on V86 task
         setIntHandler(0x0D, handler0D);      // reset standard GPF handler
         enablePreemption(currentTask);       // reenable multitasking
         return;                              // ...and I am outta here...

       case 0xFA: // CLI
         v86.tss.eflags &= ~EFLAGS_IF;
         v86.tss.eip = (UInt16)(v86.tss.eip + 1);
         break;

       case 0xFB: // STI
         v86.tss.eflags |= EFLAGS_IF;
         v86.tss.eip = (UInt16)(v86.tss.eip + 1);
         break;
      }
      iret();      // return to V86 task
      err = pop(); // pop GPF error code off stack
      o32 = a32 = 0;
   }
}

Re:Interrupt Vector Table Question

Posted: Thu Jul 22, 2004 10:25 am
by chen17981
Finally, I still have a question why it is nesscary for us to define a IDT, why we couldn't continue use the IVT in Pmode.

Re:Interrupt Vector Table Question

Posted: Thu Jul 22, 2004 10:28 am
by DennisCGc
chen17981 wrote: Finally, I still have a question why it is nesscary for us to define a IDT, why we couldn't continue use the IVT in Pmode.
Because the addresses aren't correct then anymore.....
An IVT is meant for the real mode, not for the protected mode.......

Re:Interrupt Vector Table Question

Posted: Thu Jul 22, 2004 12:57 pm
by Dreamsmith
Indeed, even if the routines in question were smart enough to handle being called from either mode, the IVT itself is too small to hold the information necessary to tell the processor what to do in order to call them. Because of its segmented architecture, 32-bit were required to specify the location of interrupt handling routines on the 16-bit 8086. On the 32-bit 80386 and later, when operating in 32-bit mode, a bare minimum of 48-bits are required (16 bit segment, but now 32 bits for the offset). Plus, to support protected mode, more information (such as privilige level) and thus even more bits are required. The IVT is simply too small to handle interrupts in protected mode, even in principle. An IDT must be created, and looking at it's structure, it's hard to imagine how a structure any smaller than that could contain the information necessary to tell the processor what to do when an interrupt occurs. There was simply no way to cram that kind of information into the IVT in a backwards compatible way -- a new structure had to be defined.