OSDev.org

The Place to Start for Operating System Developers
It is currently Sat Apr 20, 2024 12:31 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 41 posts ]  Go to page Previous  1, 2, 3
Author Message
 Post subject: Re: IDT problems
PostPosted: Sat Apr 23, 2016 9:59 am 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8561
Location: At his keyboard!
Hi,

cklie97 wrote:
Code:
(gdb) step
36               asm volatile("int $0x20");
(gdb) print $sp
$6 = (void *) 0x1067f0
(gdb) step
Breakpoint 2, 0x00100070 in intr_stub_32 ()
(gdb) print $sp
$7 = (void *) 0x1067ea


It looks like you ended up with a 16-bit gate where the CPU is pushing words (e.g. flags, CS IP) instead of pushing dwords (eflags, CS, EIP).

Try setting "IDT_FLAG_32BIT" in your IDT gates.


Cheers,

Brendan

_________________
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.


Top
 Profile  
 
 Post subject: Re: IDT problems
PostPosted: Sat Apr 23, 2016 10:17 am 
Offline

Joined: Tue Apr 19, 2016 2:11 am
Posts: 18
Brendan wrote:
It looks like you ended up with a 16-bit gate where the CPU is pushing words (e.g. flags, CS IP) instead of pushing dwords (eflags, CS, EIP).

Try setting "IDT_FLAG_32BIT" in your IDT gates.


Thank You.
This solved the problem


Top
 Profile  
 
 Post subject: Re: IDT problems
PostPosted: Fri Aug 04, 2017 7:39 am 
Offline

Joined: Wed Dec 03, 2014 1:46 pm
Posts: 15
I have a problem with setting up the IDT.

It only works partly: If I call software interrupts like "asm volatile("int $0x3");" my isr_handler recieve ISR no. 3.
So good so far. If I register an example interrupt handler and this handler gets called by the interrupt my kernel runs into trouble: ISR 13 spams my screen with "recieved isr: 13"! ISR 13 means "General Protection Fault". Also I never recieve interrups from my keyboard. I've set 0x08 for the 32BIT_FLAG at my IDT Tables and I also should not mapped PIC vector out of the IDT. So what am I missing, whats still wrong?

I compile with GCC 7.1 and BinUtils 2.28 on Windows and test with qemu. I am not sure if qemu emulates my usb keyboard into the ps/2 keyboard input, so I called the interrupt like a software interrupt.

Here is my code:
https://gitlab.com/lolxdfly/kernel

Please try to ignore the bad code design. I will recode everything after I can use new and delete. Thanks for any help.

_________________
My Code


Last edited by lolxdfly on Sat Aug 05, 2017 7:40 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: IDT problems
PostPosted: Fri Aug 04, 2017 12:55 pm 
Offline
Member
Member
User avatar

Joined: Fri Oct 27, 2006 9:42 am
Posts: 1925
Location: Athens, GA, USA
Protip: if you have a publicly accessible mirror of your source code repository on a host such as GitHub or CloudForge (which we strongly recommend having, anyway - version control is crucial for a project of this scope, and an offsite mirror is an easy and sensible precaution when using any modern DVCS), for longer sections of code you can simply give us a link to the file on the repo.

_________________
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.


Top
 Profile  
 
 Post subject: Re: IDT problems
PostPosted: Sat Aug 05, 2017 11:16 am 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5137
lolxdfly wrote:
So what am I missing, whats still wrong?

I saw a few of these bugs in your code. Perhaps one of them is the cause of your trouble?


Top
 Profile  
 
 Post subject: Re: IDT problems
PostPosted: Sat Aug 05, 2017 12:55 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 692
I don't think your interrupts are working as you expect because after you finish executing kernel_main you exit and do a CLI/HLT combination. That turns off interrupts and the HLT won't exit unless it receives a non-Maskable interrupt (not likely to occur). The CLI prevents IRQ events and so you won't get interrupts at that point. You should put an infinite loop at the end of kernel_main that does a HLT instruction inside an infinite loop while interrupts are on. HLT will block until the next interrupt at which point it continues. The infinite loop will keep it processing interrupts indefinitely.

More importantly a larger bug is that you are passing registers by value into irq_handler. You should modify irq_common_stub to be something like:
Code:
irq_common_stub:
    pusha                   #Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax

    mov %ds, %ax            #Lower 16-bits of eax = ds.
    push %eax               #save the data segment descriptor

    mov $0x10, %ax          #load the kernel data segment descriptor
    mov %ax, %ds
    mov %ax, %es
    mov %ax, %fs
    mov %ax, %gs

    cld                     #Make sure direction flag is forward. We don't know what state it is in when interrupt occurs
    push %esp               #Pass a reference to registers
    call irq_handler

    pop %ebx                #Throw away register reference
    pop %ebx                #reload the original data segment descriptor
    [snip]

The registers structure is on the stack starting at ESP so we pass ESP to irq_handler. I've also added a CLD instruction to ensure the direction flag is forward before calling into the C++ code. Then modify irq_handler in idt.cpp so that the function takes _registers_ as a reference with something like:
Code:
extern "C" void irq_handler(registers_t &regs)

You should also pass the registers_t structure to the actual handlers by reference as well. Modify idt.h so that the isr_t typedef takes a reference:
Code:
//Enables registration of callbacks for interrupts or IRQs.
typedef void (*isr_t)(registers_t &);

You have a handler for the keyboard in kernel.cpp that would need to be modified:
Code:
static void kbc_handler(registers_t &regs)

The issue with the registers structure in the IRQ handling above also needs to be made to your ISR handling as well. I leave that as a simple exercise for you.


Top
 Profile  
 
 Post subject: Re: IDT problems
PostPosted: Sat Aug 05, 2017 6:36 pm 
Offline

Joined: Wed Dec 03, 2014 1:46 pm
Posts: 15
Thanks for the answers. I went through the Known Bugs article and changed some of my code.
I also changed the pass of the registers and the irq/isr handler.
The updated version is already on my git.

Now IRQ0 spams my screen. So the Timer interrups look good so far. Sometimes (not always) I get IRQ1 when I press a key on my keyboard, but the handler(kbc_handler) does never get called. This would mean that the interrupt_handler entry is 0. I moved the handler call right behind the screen output to secure that the signal resests do not reset my int_no. Nevertheless kbc_handler does not get the call.

The Divide By Zero Test results in ISR6 (wrong opcode). That is not how it should be but all in all it is better than it was before.

I may have messed up the isr_common_stub/irq_common_stub. I'll check it later again :D

_________________
My Code


Top
 Profile  
 
 Post subject: Re: IDT problems
PostPosted: Sat Aug 05, 2017 7:06 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 692
lolxdfly wrote:
Thanks for the answers. I went through the Known Bugs article and changed some of my code.

Sometimes (not always) I get IRQ1 when I press a key on my keyboard, but the handler(kbc_handler) does never get called. This would mean that the interrupt_handler entry is 0.

There is a possibility that you get a keyboard interrupt but it occurs before you set the interrupt handlers. You should enable interrupts with STI after you hook in your interrupt handlers (not before). With that being said, when a keyboard press is registered and the interrupt is fired it will not fire another until you read the byte available on port 0x60. For your basic do nothing keyboard handler at a minimum you should read a byte from port 0x60 even if you just throw away the data for test purposes. Something like:
Code:
static void kbc_handler(registers_t &regs)
{
    screen << "Test " << endl;
    inb(0x60);
}

Since the byte has been read it will allow the next keyboard interrupt to be sent the next time a character is read.

Regarding division by 0 - how did you generate the division by zero? (What code did you use to raise that exception?)


Top
 Profile  
 
 Post subject: Re: IDT problems
PostPosted: Sun Aug 06, 2017 8:20 am 
Offline

Joined: Wed Dec 03, 2014 1:46 pm
Posts: 15
I fixed my idtentries.s code and added inb(0x60) to my kbc_handler.
My IRQs work now as expected. My kbc_handler get his call if I press a key.

I tried to raise the division by 0 exception with this piece of code at my kernel_main:
Code:
   int b = 2;
   int z = 0;
   int err = b / z; //no ISR up to here
   screen << err; //ISR6 code 0!?

I only get ISR6 in the last line. All code before runs without ISRs. Did I missunderstand the ISR or does my system not work?

_________________
My Code


Top
 Profile  
 
 Post subject: Re: IDT problems
PostPosted: Sun Aug 06, 2017 9:15 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 692
Just woke up. Some versions of GCC and CLANG will replace undefined behavior with a trap. Seems like GCC 7.10 is reducing division by zero to a UD2 instruction. UD2 is a valid opcode that raises undefined #UD exception (ISR6). Seems that GCC 7.1 is a compiler that is now generating UD2 for something it knows is division by zero. If you use
Quote:
objdump -Dx kernel.bin

to output the generated code and look at the bottom of kernel_main you will likely find UD2. You can check this out on Godbolt online compiler with GCC 7.10 you will find that:
Code:
int main()
{
   int b = 2;
   int z = 0;
   int err = b / z; //no ISR up to here
   return err;
}

reduces to:
Code:
main:
   ud2

You can play with this example on Godbolt. If you change it to gcc 6.3 or earlier it generates code that will do division by zero as you'd expect.

To get around this you can use inline assembly to force division by zero with something like:
Code:
int err = 2;
asm volatile("divb %1" : "+a"(err) : "r"(0));

This will simply pass 0 into a register and we use DIV by that register to generate our ISR0 division by zero.

Alternatively you can mark the z input variables in your own division by zero code as volatile. This will prevent GCC from optimizing the code to division by zero because the volatile input could be modified externally:
Code:
   int b = 2;
   volatile int z = 0;
   int err = b / z; //no ISR up to here


Last edited by MichaelPetch on Sun Aug 06, 2017 12:20 pm, edited 2 times in total.

Top
 Profile  
 
 Post subject: Re: IDT problems
PostPosted: Sun Aug 06, 2017 9:44 am 
Offline

Joined: Wed Dec 03, 2014 1:46 pm
Posts: 15
I already thought that the compiler optimizes the exception away because of the -O2 flag.
The DIVB raises ISR0. So you're right.
Thanks for all the help.

_________________
My Code


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 41 posts ]  Go to page Previous  1, 2, 3

All times are UTC - 6 hours


Who is online

Users browsing this forum: Google [Bot] and 54 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group