I am currently trying to build my first OS with the help of JamesM's tutorial and the OSDev wiki. I run my code with qemu-system-i386.

I have managed to load the GDT and the IDT (and so far they seem to be correct), but, although I have remapped the PIC and filled the IDT accordingly, I cannot get the IRQs to work. As advised on the wiki, I have checked that I receive software interrupts, and I have enabled all the IRQs on the PIC mask.

sti before iret is pointless, as iret reloads rflags. Do you ever set the interrupt flag (sti)?

That was it, thank you. I never thought of doing that since I don't believe JamesM ever does it in his tutorial.Just to be sure, is it correct if I put sti right after lidt ?

Code:

.global idt_flushidt_flush: mov 4(%esp), %eax lidt (%eax) sti ret

Anyway, this looks like its working, but I am getting a General Protection Fault now. I managed to pinpoint the problem : the irq_handler function overwrites the stack (where the old value of the ds descriptor is stored) when it is called by irq_common_stub :

Before tick++ is called, %esp = 0x108c04.After it is called, we still have %esp = 0x108c04 but the value at %esp + 4 = 0x108c08 (where we stored %ds) was overwritten with another value (0x00102641, I don't really know what it could be).Then when printf is called, the value at %esp + 8 = 0x108c0c is overwritten with another value (0x1) but %esp still hasn't moved.

Then the stack's behavior goes back to normal and values don't get overwritten anymore. Thus a General Protection Fault occurs because we then load %ds with 0x00102641.

The 32-bit System V ABI doesn't guarantee that structures and data passed by value will be unchanged in a function. The compiler is free to reuse that stack space for its own data. Arguments passed (on the stack) to a function are owned by the called function, not the caller. This is a bug in the Malloy's tutorial from which that code comes from:

Code:

void irq_handler(registers_t regs) {

is the issue. you want to pass registers_t *regs instead. That will require passing the address of the registers structure into irq_handler in the assembly stub code. You should also be passing registers_t *regs into the interrupt handlers as well. I wrote a Reddit post recently about this issue and a fix that can be applied: https://www.reddit.com/r/osdev/comments ... pt/ef4bxnk

The 32-bit System V ABI doesn't guarantee that structures and data passed by value will be unchanged in a function. The compiler is free to reuse that stack space for its own data. Arguments passed (on the stack) to a function are owned by the called function, not the caller. This is a bug in the Malloy's tutorial from which that code comes from:

Code:

void irq_handler(registers_t regs) {

is the issue. you want to pass registers_t *regs instead. That will require passing the address of the registers structure into irq_handler in the assembly stub code. You should also be passing registers_t *regs into the interrupt handlers as well. I wrote a Reddit post recently about this issue and a fix that can be applied: https://www.reddit.com/r/osdev/comments ... pt/ef4bxnk

Thank you! It almost works now.Indeed, if I launch my OS through GDB, it seems to run flawlessly. The problem is that if I launch it directly through QEMU, I still get a General Protection Fault, and I cannot pinpoint the problem now that GDB thinks there aren't any problem.If I print the values of the registers when the exception is raised, I get the following values :

The multiboot spec doesn't guarantee that the CS, DS, ES, SS segment selectors have any particular value. So in one environment CS could be 0x08 or it could 0x10 in another etc. You'll actually find the values differ if you run your kernel with QEMU via the -kernel option (CS is usually 0x08) versus the -cdrom option (CS via real GRUB may be 0x10). This all matters because in your gdt_flush code you have commented out an important line:

The CLI/HLT should be removed. I assume this may have been placed there for testing purposes. You should also put HLT in an infinite loop at the end of kernel_main where interrupts are still enabled so that your kernel can continue to process interrupts without leaving your kernel. Add something like this to the end of kernel_main:

Code:

while(1) asm ("hlt");

Before calling your irq or ISR handler the common stub should clear the direction flag with CLD before calling into the C/C++ function. This is required by the 32-bit System V ABI as well.

Who is online

Users browsing this forum: No registered users and 12 guests

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