OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Apr 18, 2024 2:48 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 45 posts ]  Go to page Previous  1, 2, 3
Author Message
 Post subject: Re: Very lost on botched interrupts causing triple fault
PostPosted: Mon Oct 12, 2020 10:17 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5137
Then the answer is yes, you did set the interrupt flag.

Are you receiving IRQs from any hardware other than the keyboard controller? For example, the timer is probably configured to raise IRQ0.


Top
 Profile  
 
 Post subject: Re: Very lost on botched interrupts causing triple fault
PostPosted: Mon Oct 12, 2020 10:18 pm 
Offline
Member
Member
User avatar

Joined: Sun Oct 11, 2020 9:46 pm
Posts: 370
Location: United States
Octocontrabass wrote:
Then the answer is yes, you did set the interrupt flag.

Are you receiving IRQs from any hardware other than the keyboard controller? For example, the timer is probably configured to raise IRQ0.


My IRQ handler is one function, that takes an argument of interrupt code. I don't really understand what you mean... I'm not getting any notifications of interrupts like I programmed it to.

_________________
Skylight: https://github.com/austanss/skylight

I make stupid mistakes and my vision is terrible. Not a good combination.

NOTE: Never respond to my posts with "it's too hard".


Top
 Profile  
 
 Post subject: Re: Very lost on botched interrupts causing triple fault
PostPosted: Mon Oct 12, 2020 10:20 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5137
Does your IRQ handler get called at all? Try running it in a debugger. You'll be able to set a breakpoint to see.


Top
 Profile  
 
 Post subject: Re: Very lost on botched interrupts causing triple fault
PostPosted: Mon Oct 12, 2020 10:20 pm 
Offline
Member
Member
User avatar

Joined: Sun Oct 11, 2020 9:46 pm
Posts: 370
Location: United States
Octocontrabass wrote:
Does your IRQ handler get called at all? Try running it in a debugger. You'll be able to set a breakpoint to see.

I don't know how I would run it in a debugger, and fwiw, some jackass stripped the build of it's debug symbols.

_________________
Skylight: https://github.com/austanss/skylight

I make stupid mistakes and my vision is terrible. Not a good combination.

NOTE: Never respond to my posts with "it's too hard".


Top
 Profile  
 
 Post subject: Re: Very lost on botched interrupts causing triple fault
PostPosted: Mon Oct 12, 2020 10:23 pm 
Offline
Member
Member
User avatar

Joined: Sun Oct 11, 2020 9:46 pm
Posts: 370
Location: United States
ISR.asm
Code:
%macro ISRWithoutErrorCode 1
  global isr%1
  isr%1:
        cli
        push byte 0
        push byte %1
        jmp CommonISRStub
%endmacro

%macro ISRWithErrorCode 1
  global isr%1
  isr%1:
        cli
        push byte %1
        jmp CommonISRStub
%endmacro

ISRWithoutErrorCode 0
ISRWithoutErrorCode 1
ISRWithoutErrorCode 2
ISRWithoutErrorCode 3
ISRWithoutErrorCode 4
ISRWithoutErrorCode 5
ISRWithoutErrorCode 6
ISRWithErrorCode 7
ISRWithoutErrorCode 8
ISRWithErrorCode 9
ISRWithErrorCode 10
ISRWithErrorCode 11
ISRWithErrorCode 12
ISRWithErrorCode 13
ISRWithoutErrorCode 14
ISRWithoutErrorCode 15
ISRWithoutErrorCode 16
ISRWithoutErrorCode 17
ISRWithoutErrorCode 18
ISRWithoutErrorCode 19
ISRWithoutErrorCode 20
ISRWithoutErrorCode 21
ISRWithoutErrorCode 22
ISRWithoutErrorCode 23
ISRWithoutErrorCode 24
ISRWithoutErrorCode 25
ISRWithoutErrorCode 26
ISRWithoutErrorCode 27
ISRWithoutErrorCode 28
ISRWithoutErrorCode 29
ISRWithoutErrorCode 30
ISRWithoutErrorCode 31

EXTERN ISRHandler

CommonISRStub:
        pusha

        mov ax, ds
        push eax

        mov ax, 0x10
        mov ds, ax
        mov es, ax
        mov fs, ax
        mov gs, ax

        call ISRHandler

        pop eax
        mov ds, ax
        mov es, ax
        mov fs, ax
        mov gs, ax

        popa
        add esp, 8
        sti
        iret

from GDT.cpp
Code:
struct Registers
{
        uint32_t ds;
        uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
        uint32_t interruptNumber, errorCode;
        uint32_t eip, cs, eflags, useresp, ss;
};


void ISRHandlerImpl(Registers& registers)
{
        if (registers.interruptNumber == 1 || registers.interruptNumber == 33) {
                auto keycode = inb(0x60);

                if (keycode < 0) {
                        return;
                }

                Terminal::instance->write(keycode);
                Terminal::instance->write("\n");
        }
        Terminal::instance->write("Interrupt: ");
        Terminal::instance->write(registers.interruptNumber);
        Terminal::instance->write("\n");
}

void ISRHandler(Registers registers)
{
        outb(0xA0, 0x20);
        ISRHandlerImpl(registers);
        outb(0x20, 0x20);
}

_________________
Skylight: https://github.com/austanss/skylight

I make stupid mistakes and my vision is terrible. Not a good combination.

NOTE: Never respond to my posts with "it's too hard".


Top
 Profile  
 
 Post subject: Re: Very lost on botched interrupts causing triple fault
PostPosted: Mon Oct 12, 2020 10:54 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 692
You need to add entries to your IDT for the IRQs from 0x20 to 0x2f (32 to 47). Right now your interrupts aren't being redirected into a handler like the ISRs you already have. As well your going to run into problems if you build with optimizations. `CommonISRStub` builds the register structure by value and not by reference. This can cause the compiler to generate code that can corrupt the saved interrupt stack. `CommonISRStub` should push the address of the register structure as the first parameter to ISRHandler. Something like:
Code:
CommonISRStub:
        pusha

        mov ax, ds
        push eax

        mov ax, 0x10
        mov ds, ax
        mov es, ax
        mov fs, ax
        mov gs, ax

        cld
        push esp
        call ISRHandler

        pop eax
        pop eax
        mov ds, ax
        mov es, ax
        mov fs, ax
        mov gs, ax

        popa
        add esp, 8
;       sti
        iret

Then ISRHandler should be defined this way:
Code:
void ISRHandler(Registers& registers)
instead of
Code:
void ISRHandler(Registers registers)
.

You also don't handle the EOIs properly in ISRHandler. You shouldn't put an STI at the end of CommonISRStub. And one serious concern I have is that your Linker script and startup code doesn't call the global constructors (the constructors of objects at global scope). This could cause serious problems for any objects that were supposed to have constructors initialize objects.


Top
 Profile  
 
 Post subject: Re: Very lost on botched interrupts causing triple fault
PostPosted: Tue Oct 13, 2020 5:36 am 
Offline
Member
Member
User avatar

Joined: Sun Oct 11, 2020 9:46 pm
Posts: 370
Location: United States
MichaelPetch wrote:
You need to add entries to your IDT for the IRQs from 0x20 to 0x2f (32 to 47). Right now your interrupts aren't being redirected into a handler like the ISRs you already have. As well your going to run into problems if you build with optimizations. `CommonISRStub` builds the register structure by value and not by reference. This can cause the compiler to generate code that can corrupt the saved interrupt stack. `CommonISRStub` should push the address of the register structure as the first parameter to ISRHandler. Something like:
Code:
CommonISRStub:
        pusha

        mov ax, ds
        push eax

        mov ax, 0x10
        mov ds, ax
        mov es, ax
        mov fs, ax
        mov gs, ax

        cld
        push esp
        call ISRHandler

        pop eax
        pop eax
        mov ds, ax
        mov es, ax
        mov fs, ax
        mov gs, ax

        popa
        add esp, 8
;       sti
        iret

Then ISRHandler should be defined this way:
Code:
void ISRHandler(Registers& registers)
instead of
Code:
void ISRHandler(Registers registers)
.

You also don't handle the EOIs properly in ISRHandler. You shouldn't put an STI at the end of CommonISRStub. And one serious concern I have is that your Linker script and startup code doesn't call the global constructors (the constructors of objects at global scope). This could cause serious problems for any objects that were supposed to have constructors initialize objects.


I don't have any global constructors...

_________________
Skylight: https://github.com/austanss/skylight

I make stupid mistakes and my vision is terrible. Not a good combination.

NOTE: Never respond to my posts with "it's too hard".


Top
 Profile  
 
 Post subject: Re: Very lost on botched interrupts causing triple fault
PostPosted: Tue Oct 13, 2020 12:02 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 692
I should have looked closer at the code. I made a false assumption looking at your GDT.cpp file and boot.S. I assumed that there is a global Terminal object in your system but you create it on the stack inside kernel_main. My assumption that there was a global `Terminal` that was already initialized was because in boot.S you call `loadGDT` that will setup the ISRs (and eventually a proper one for the timer and the keyboard), and then before you call `kernel_main` from boot.S you enable interrupts with `STI`.

If someone were to hit a key on the keyboard after you did `STI` (in boot.S) and before the constructor of `Terminal` is called in `kernel_main` then this code in ISRHandlerImpl:
Code:
Terminal::instance->write(keycode);
will attempt to use `instance` before it has been set to anything which could cause problems.

Usually for a C++ singleton pattern most people create something like a static `instance()` function inside the class which checks to see if the static instance variable in the object is nullptr and if it is it internally creates a new copy of the object and returns that new pointer (and sets the instance variable with it) otherwise it just returns the instance variable. There is of course a cleaner way and that is for the `instance()` function to simply create a static object of itself and return that object reference. Ultimately you call `instance()` this way:
Code:
Terminal::instance()->write(keycode);
This way you would be guaranteed to have a valid instance returned. This does have the disadvantage of potentially having more overhead on each call.


Top
 Profile  
 
 Post subject: Re: Very lost on botched interrupts causing triple fault
PostPosted: Tue Oct 13, 2020 1:15 pm 
Offline
Member
Member
User avatar

Joined: Sun Oct 11, 2020 9:46 pm
Posts: 370
Location: United States
MichaelPetch wrote:
I should have looked closer at the code. I made a false assumption looking at your GDT.cpp file and boot.S. I assumed that there is a global Terminal object in your system but you create it on the stack inside kernel_main. My assumption that there was a global `Terminal` that was already initialized was because in boot.S you call `loadGDT` that will setup the ISRs (and eventually a proper one for the timer and the keyboard), and then before you call `kernel_main` from boot.S you enable interrupts with `STI`.

If someone were to hit a key on the keyboard after you did `STI` (in boot.S) and before the constructor of `Terminal` is called in `kernel_main` then this code in ISRHandlerImpl:
Code:
Terminal::instance->write(keycode);
will attempt to use `instance` before it has been set to anything which could cause problems.

Usually for a C++ singleton pattern most people create something like a static `instance()` function inside the class which checks to see if the static instance variable in the object is nullptr and if it is it internally creates a new copy of the object and returns that new pointer (and sets the instance variable with it) otherwise it just returns the instance variable. There is of course a cleaner way and that is for the `instance()` function to simply create a static object of itself and return that object reference. Ultimately you call `instance()` this way:
Code:
Terminal::instance()->write(keycode);
This way you would be guaranteed to have a valid instance returned. This does have the disadvantage of potentially having more overhead on each call.

Would it also be possible, since kernel_main does stack-allocate the Terminal instance, that the Terminal instance is being destroyed after kernel_main ends? Or do we not have luxuries like that in freestanding environments?

_________________
Skylight: https://github.com/austanss/skylight

I make stupid mistakes and my vision is terrible. Not a good combination.

NOTE: Never respond to my posts with "it's too hard".


Top
 Profile  
 
 Post subject: Re: Very lost on botched interrupts causing triple fault
PostPosted: Tue Oct 13, 2020 1:20 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5137
rizxt wrote:
Would it also be possible, since kernel_main does stack-allocate the Terminal instance, that the Terminal instance is being destroyed after kernel_main ends?

Yes.


Top
 Profile  
 
 Post subject: Re: Very lost on botched interrupts causing triple fault
PostPosted: Tue Oct 13, 2020 1:32 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 692
Quote:
Would it also be possible, since kernel_main does stack-allocate the Terminal instance, that the Terminal instance is being destroyed after kernel_main ends? Or do we not have luxuries like that in freestanding environments?


The object on the stack would go out of scope as soon as `kernel_main` returns. Which means the destructor will be called and the space occupied by that object on the stack will be released. You won't be able to rely on any of the non static member variables in that object being valid anymore nor will the instance pointer be pointing to a valid object anymore (it would be pointing at the one that was on the stack). That will pose a problem in your code since you don't put an endless `hlt` loop in your `kernel_main` but let it return back to Boot.S to do the loop there.

There is a good chance that if you got interrupts going that and you don't fix the Terminal object and how you use it you may not see the output you are expecting in the ISRHandlerImpl (or it may just crash).


Top
 Profile  
 
 Post subject: Re: Very lost on botched interrupts causing triple fault
PostPosted: Tue Oct 13, 2020 1:41 pm 
Offline
Member
Member
User avatar

Joined: Sun Oct 11, 2020 9:46 pm
Posts: 370
Location: United States
MichaelPetch wrote:
Quote:
Would it also be possible, since kernel_main does stack-allocate the Terminal instance, that the Terminal instance is being destroyed after kernel_main ends? Or do we not have luxuries like that in freestanding environments?


The object on the stack would go out of scope as soon as `kernel_main` returns. Which means the destructor will be called and the space occupied by that object on the stack will be released. You won't be able to rely on any of the non static member variables in that object being valid anymore nor will the instance pointer be pointing to a valid object anymore (it would be pointing at the one that was on the stack). That will pose a problem in your code since you don't put an endless `hlt` loop in your `kernel_main` but let it return back to Boot.S to do the loop there.

There is a good chance that if you got interrupts going that and you don't fix the Terminal object and how you use it you may not see the output you are expecting in the ISRHandlerImpl (or it may just crash).

I figured that would pose a problem, I just was unsure, and wasn't going to touch code I didn't write if I was unsure.

_________________
Skylight: https://github.com/austanss/skylight

I make stupid mistakes and my vision is terrible. Not a good combination.

NOTE: Never respond to my posts with "it's too hard".


Top
 Profile  
 
 Post subject: Re: Very lost on botched interrupts causing triple fault
PostPosted: Tue Oct 13, 2020 2:20 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 692
The quickest thing I can think of is remove the instance variable from you Terminal class altogether. Define your Terminal class this way:
Code:
#pragma once

#include "stddef.h"
#include "stdint.h"

class Terminal
{
        static const size_t VGA_WIDTH = 80;
        static const size_t VGA_HEIGHT = 25;

        size_t row;
        size_t column;
        uint16_t* buffer;

public:
        static constexpr const char* Status = "$WHITE![$LIGHT_BLUE!--$WHITE!] $LIGHT_GREY!\0";
        static constexpr const char* Good = "$WHITE![$LIGHT_GREEN!:)$WHITE!] $LIGHT_GREY!\0";
        static constexpr const char* EOL = "\n";
        static Terminal &instance();

        void put_entry_at(char c, uint8_t color, size_t x, size_t y);
        void put_char(char c, uint8_t color);
        void write(const char* data, size_t size);
        void write(const char* data);
        void write(int num);
        void println(const char* data = "");
        void shift();

private:
        Terminal();
        Terminal(Terminal const&);
        void operator=(Terminal const&);
};

template<typename T>
Terminal& operator<<(Terminal& term, T data)
{
        term.write(data);
        return term;
}

template<typename T>
Terminal* operator<<(Terminal* term, T data)
{
        term->write(data);
        return term;
}
I have deleted the `instance` variable (in the header and in the Terminal.cpp file) and created an `instance` function that returns a Terminal reference. I have also made the constructor private so that you can't create a Terminal object directly. In your Terminal.cpp you can add this new instance function:
Code:
Terminal &Terminal::instance()
{
        static Terminal instance;

        return instance;
}
This has a static `Terminal` object called 'instance' in it. We just return a reference to that object to the caller. The instance() function will take care of initializing `instance` by calling its constructor if needed. This is what produces a singleton object. To use it in Kernel.cpp you'd do something like:
Code:
void kernel_main()
{
        Terminal &terminal = Terminal::instance();
        terminal << logo;
        terminal << Terminal::EOL;

        // rest of code here
}
In your ISRHandlerImpl you could use it like:
Code:
                Terminal::instance().write(keycode);
                Terminal::instance().write("\n");
Depending on your compiler you may also have to add the option `'-fno-threadsafe-statics'` to meson.build compile arguments. This is because many compilers will produce thread safe code around the static local object ('instance' in this case). This could generate calls to functions you haven't implemented that maintain thread safe access to these objects. Implementing the required functions to maintain thread safety would be the best course of action in the long term. There is a page somewhere on the OSDev Wiki about the functions that need to be implemented.


Last edited by MichaelPetch on Wed Oct 14, 2020 9:32 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Very lost on botched interrupts causing triple fault
PostPosted: Tue Oct 13, 2020 4:53 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 692
rizxt wrote:
I don't know how I would run it in a debugger, and fwiw, some jackass stripped the build of it's debug symbols.
. I build with
Code:
env CXX=clang++ CC=clang meson _build --buildtype debug
And I debug with QEMU and GDB with something like:
Code:
qemu-system-i386 -cdrom _build/NovaVita.iso -S -s -no-reboot -no-shutdown &

gdb ./_build/NovaCor/Kernel/NovaVita.kernel.debug \
        -ex 'target remote localhost:1234' \
        -ex 'layout src' \
        -ex 'layout regs' \
        -ex 'break _start' \
        -ex 'continue'
You can set a start breakpoint anywhere. You could make it `kernel_main` instead of `_start`. While debugging if you need to debug assembly code you can use `layout asm` at the GDB prompt. You can find tutorials and cheat sheets online for more detailed GDB commands once the debugger is running.


Top
 Profile  
 
 Post subject: Re: Very lost on botched interrupts causing triple fault
PostPosted: Wed Oct 14, 2020 10:50 am 
Offline
Member
Member
User avatar

Joined: Sun Oct 11, 2020 9:46 pm
Posts: 370
Location: United States
I have determined the cause of my lack of interrupt functionality. The interrupts are being handled, however due to the piece of **** of a terminal class I have, the terminal doesn't display them. Thank you everyone, for your support. I can work on the terminal myself, however.

_________________
Skylight: https://github.com/austanss/skylight

I make stupid mistakes and my vision is terrible. Not a good combination.

NOTE: Never respond to my posts with "it's too hard".


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

All times are UTC - 6 hours


Who is online

Users browsing this forum: Google [Bot], Majestic-12 [Bot] and 103 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