RTC interrupts stop after my first IPI

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
kemosparc
Member
Member
Posts: 207
Joined: Tue Oct 29, 2013 1:13 pm

RTC interrupts stop after my first IPI

Post by kemosparc »

Hi,

I have a problem regarding the RTC and IPI.

I setup the RTC and it works fine as long as I did not send any IPI.

After starting an aditional AP and sending it the first IPI the RTC intrrupts stops, although the PIT continue to work.

Is this normal?

Thanks,
Karim.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: RTC interrupts stop after my first IPI

Post by Brendan »

Hi,
kemosparc wrote:After starting an aditional AP and sending it the first IPI the RTC intrrupts stops, although the PIT continue to work.

Is this normal?
If you forget to send the EOI to the local APIC (after receiving the IPI), and if the PIT uses a higher priority interrupt vector than the IPI, and if the RTC uses a lower priority interrupt vector than the IPI, then it's normal.


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.
kemosparc
Member
Member
Posts: 207
Joined: Tue Oct 29, 2013 1:13 pm

Re: RTC interrupts stop after my first IPI

Post by kemosparc »

Thanks for the reply.

I hook my PIT on 32 (IRQ0), RCT on 40 (IRQ8), and the IPI is sent to interrupt 64. I only send IPIs to the AP, the BSP does not receieve any.

I do send EOI by the AP at the end of the IPI service routine.

How can I adjust the priorities so the RTC continue to fire after sending the IPI.


Thanks,
Karim.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: RTC interrupts stop after my first IPI

Post by Brendan »

Hi,
kemosparc wrote:I hook my PIT on 32 (IRQ0), RCT on 40 (IRQ8), and the IPI is sent to interrupt 64. I only send IPIs to the AP, the BSP does not receieve any.

I do send EOI by the AP at the end of the IPI service routine.

How can I adjust the priorities so the RTC continue to fire after sending the IPI.
In that case, interrupt vectors 32 and 40 are already lower priority than interrupt vector 64; and something else must be going on. However, whatever is going on I can't think of a plausible explanation that fits the symptoms and/or the details provided (and/or assumed by me).

Are you using PIC chips or IO APIC/s?

Does "starting an additional AP" really mean an additional AP (e.g. one or more APs were already running and you start an additional AP), or does it actually mean "starting an additional CPU" (e.g. BSP is running and no APs are running, and you start the first AP)?

Are you sure that sending the first IPI causes the RTC to stop; and that the RTC doesn't just send one IRQ regardless (e.g. you forgot to read "RTC Register C")?

If sending the first IPI causes the RTC to stop, what is the first IPI? Do you mean the INIT IPI sent when starting the AP, or do you mean the first IPI after the CPU has been started (e.g. the interrupt 64)?

After sending the IPI; would the RTC's IRQ occur before the PIT's IRQ? Is it possible that the first IRQ (which just happens to be the RTC's IRQ) goes to the AP CPU and the AP CPU isn't setup to handle it; and that if the PIT's IRQ occurred first then the PIT would stop working and the RTC would keep running?

Which chipset is this on? Specifically, is the hardware real, or are the PIC chips or either timer being (partially or fully) emulated by the firmware's SMM code (e.g. maybe the firmware is using HPET and SMM to emulate a PIT that doesn't exist, and the firmware's emulation is buggy causing the PIT's emulation to continue when something is wrong and all IRQs should've stopped).

Does the same problem happen on all computers, or just some? Does it happen on emulators (e.g. Bochs)?


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.
kemosparc
Member
Member
Posts: 207
Joined: Tue Oct 29, 2013 1:13 pm

Re: RTC interrupts stop after my first IPI

Post by kemosparc »

Okay, answering your questions,

I am using PIC.

I start up one AP, and I send INIP and ISIP successfully and the RTC still work and print on the screen the ticks.

I send the IPI to int 64 on the AP from the BSP PIT. So every 10 interrupts on 32, the PIT, I send an IPI to the AP. And the interrupt service routine of int 64 increments a variable and prints it on the screen. So this print by int 64 keeps on working and never stop. Also I print a variable being incremented inside the PIT int 32 service routine to make sure that the PIT is firing and never stops.

Also, the RTC has a variable that it keeps on incrementing each time int 40 is fired, and print it on the screen.

As soon as the PIT get 10 interrupts and it is time to send the IPI, as soon as the IPI is sent, the RTC counter on the screen stops, while the PIT on the BSP and int 64 on the AP keeps on printing and incrementing.

When I comment out the IPI sending from the PIT, this makes the RTC continue to work.

More precisely when I execute this code, the problem occurs:

Code: Select all

        uint32_t tmp = 1;
        uint8_t irq = 64;
        uint32_t core_id = tmp << 24;
        Utils::writeLocalAPIC(LAPIC_ICR1, core_id);
        Utils::writeLocalAPIC(LAPIC_ICR0, 0b00000000000000000100000000000000| irq);



And if the PIT continue to work and the int 64 on the AP continue to serve the IPIs initiated from the PIT, this means the the EOI is done correctly, right ?

I use QEMU and this symptom occurs on QEMU.

Thanks,
Karim.
User avatar
xenos
Member
Member
Posts: 1121
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: RTC interrupts stop after my first IPI

Post by xenos »

I would try running the code in Bochs, as it gives you a lot more detailed debug output and can tell you about the state of the APIC and interrupt delivery.
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
kemosparc
Member
Member
Posts: 207
Joined: Tue Oct 29, 2013 1:13 pm

Re: RTC interrupts stop after my first IPI

Post by kemosparc »

Hi,

I have a serious problem with Bochs to make it work with more than 2048 MB, although I have compiled it with ramfile support yet it does not work; I need 4GB for my kernel to work.

I did not want to present code here as it might make more confusion that clearance, but I will try present as much as I can to show my problem,may be there is something that I cannot see and others may pin point easily.

First here is my kernel main C function:


Code: Select all


extern "C" void kernel_main(uint64_t initial_stack_start_address,uint64_t initial_stack_end_address)
{
    if ( bsp_flag[1] == 0 ) bsp_flag[1] = 1;
    else
    {
        kernelPageManager.enablePageDirectory();
        uint8_t core_id = Utils::getAPICId();
        kernelPageManager.cloneCoreStack(core_id,initial_stack_start_address,initial_stack_end_address);
        uint32_t apic_ap_svr = Utils::readLocalAPIC(LAPIC_SVR);
        Utils::writeLocalAPIC(LAPIC_SVR, apic_ap_svr | LAPIC_SVR_APIC_ENABLE);
        sfence();
        interruptManagers[core_id]->initialize();
        coreManager->setCurrentKernelPageManager(core_id,&kernelPageManager);
        coreManager->getAPPITScheduler(core_id)->setCoreManager(coreManager);
        interruptManagers[core_id]->registerInterrupt(coreManager->getTimerIRQ(core_id),coreManager->getAPPITScheduler(core_id));
        bsp_flag[1] = 2;
        coreManager->touch(core_id);
        interruptManagers[0]->registerInterrupt(IRQ8,rtcTimer);
        return;
    }

    video.initialize();
    video.clearScreen(COLOR_BLACK);
    memoryPhysicalLayout.initialize();
    video.putString("Memory Size: ",COLOR_RED,COLOR_LIGHT_BROWN);
    video.putDecimal(memoryPhysicalLayout.getMemorySize()/(1024*1024),COLOR_RED,COLOR_LIGHT_BROWN);
    video.putString(" MB\n",COLOR_RED,COLOR_LIGHT_BROWN);
    kernel_kmalloc.initialize(&memoryPhysicalLayout,MEM_START_ADDR,memoryPhysicalLayout.getMemorySize());
    kmalloc_ptr = & kernel_kmalloc;

    kernelPageManager.initializePaging (kmalloc_ptr,memoryPhysicalLayout.getMemorySize(),0x2000/*,0x10000*/,initial_stack_start_address,initial_stack_end_address);

    PCIConfigHeaderManager * pciConfigHeaderManager =  new PCIConfigHeaderManager();
    taskManager = new TaskManager();
    currentkernelPageManager = &kernelPageManager;
    taskManager->addTask(&kernelPageManager,0,0);
    coreManager = new CoreManager(taskManager);
    coreManager->setCurrentKernelPageManager(0,&kernelPageManager);
    kernelPageManager.createCoresStacks(coreManager->getCoreCount());
    interruptManagers  = (InterruptManager **) kmalloc_ptr->kmalloc(sizeof(InterruptManager *)*coreManager->getCoreCount());
    for ( uint16_t i = 0 ; i < coreManager->getCoreCount() ; i++)
        interruptManagers[i] = new InterruptManager();

    rtcTimer  = new RTCTimer();
    interruptManagers[0]->registerInterrupt(IRQ8,rtcTimer);
    rtcTimer->init();
    pitScheduler = new PITScheduler();
    pitScheduler->set_initial_stack_start_address(initial_stack_start_address);

    for ( uint16_t i = 0 ; i < coreManager->getCoreCount() ; i++)
    {
        coreManager->startupCore(i,APBOOT_ADDR_4K,APIRQ0,taskManager);
    }
    for ( uint16_t i = 0 ; i < coreManager->getCoreCount() ; i++)
    {
        if ( !coreManager->isBSP(i))
            interruptManagers[i]->registerInterrupt(coreManager->getTimerIRQ(i),coreManager->getAPPITScheduler(i));
    }
    pitScheduler->setCoreManager(coreManager);

    interruptManagers[0]->registerInterrupt(IRQ0,pitScheduler); // Until here everything works fine
    interruptManagers[0]->registerInterrupt(IRQ8,rtcTimer);

}

My interrupt handlers are based on a manager class and interrupt handler abstract class

Code: Select all

class InterruptManager
{
    private:
        InterruptDescriptorTable * interruptDescriptorTable;
        InterruptHandler * interruptHandlers [IDT_SIZE];
        void irqSetMask(unsigned char IRQline);
        void irqClearMask(unsigned char IRQline);
    public:
        void initialize();
        InterruptManager();
        bool registerInterrupt(uint8_t int_no,InterruptHandler * interruptHandler);
        bool serviceInterrupt (struct interrupted_context * ic);
        ~InterruptManager();
};

//*****************************************************************



extern Video video;
extern InterruptDescriptorTablePointer interruptDescriptorTablePointer;

void InterruptManager::irqSetMask(unsigned char IRQline)
{
    uint16_t port;
    uint8_t value;

    if(IRQline < 8) {
        port = PIC1_DATA;
    } else {
        port = PIC2_DATA;
        IRQline -= 8;
    }
    value = Ports::inportb(port) | (1 << IRQline);
    Ports::outportb(port, value);

}
void InterruptManager::irqClearMask(unsigned char IRQline)
{
    uint16_t port;
    uint8_t value;

    if(IRQline < 8) {
        port = PIC1_DATA;
    } else {
        port = PIC2_DATA;
        IRQline -= 8;
    }
    value = Ports::inportb(port) & ~(1 << IRQline);
    Ports::outportb(port, value);
    Ports::outportl(0x80,Ports::inportl(0x80));

}
void InterruptManager::initialize()
{

    for ( int i = 0 ; i  < IDT_SIZE ; i++)
        interruptHandlers[i] = NULL;
    asm volatile("cli");

    Ports::outportb(PIC1_DATA, 0xff);
    Ports::outportb(PIC2_DATA, 0xff);

    Ports::outportb(0x20, 0x11);
    Ports::outportb(0xA0, 0x11);
    Ports::outportb(0x21, 0x20);
    Ports::outportb(0xA1, 0x28);
    Ports::outportb(0x21, 0x04);
    Ports::outportb(0xA1, 0x02);
    Ports::outportb(0x21, 0x01);
    Ports::outportb(0xA1, 0x01);

    for ( unsigned char c = 0 ; c < 48 ; c++)
        irqSetMask(c);


    interruptDescriptorTable->setInterruptDescriptorTableEntry(0, (uint64_t)isr0, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(1, (uint64_t)isr1, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(2, (uint64_t)isr2, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(3, (uint64_t)isr3, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(4, (uint64_t)isr4, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(5, (uint64_t)isr5, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(6, (uint64_t)isr6, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(7, (uint64_t)isr7, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(8, (uint64_t)isr8, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(9, (uint64_t)isr9, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(10, (uint64_t)isr10, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(11, (uint64_t)isr11, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(12, (uint64_t)isr12, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(13, (uint64_t)isr13, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(14, (uint64_t)isr14, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(15, (uint64_t)isr15, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(16, (uint64_t)isr16, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(17, (uint64_t)isr17, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(18, (uint64_t)isr18, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(19, (uint64_t)isr19, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(20, (uint64_t)isr20, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(21, (uint64_t)isr21, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(22, (uint64_t)isr22, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(23, (uint64_t)isr23, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(24, (uint64_t)isr24, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(25, (uint64_t)isr25, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(26, (uint64_t)isr26, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(27, (uint64_t)isr27, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(28, (uint64_t)isr28, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(29, (uint64_t)isr29, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(30, (uint64_t)isr30, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(31, (uint64_t)isr31, 0x08, 0x8E);

    interruptDescriptorTable->setInterruptDescriptorTableEntry(32, (uint64_t)irq0, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(33, (uint64_t)irq1, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(34, (uint64_t)irq2, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(35, (uint64_t)irq3, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(37, (uint64_t)irq5, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(38, (uint64_t)irq6, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(39, (uint64_t)irq7, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(40, (uint64_t)irq8, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(41, (uint64_t)irq9, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(42, (uint64_t)irq10, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(43, (uint64_t)irq11, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(44, (uint64_t)irq12, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(45, (uint64_t)irq13, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(46, (uint64_t)irq14, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(47, (uint64_t)irq15, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(48, (uint64_t)irq16, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(49, (uint64_t)irq17, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(50, (uint64_t)irq18, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(51, (uint64_t)irq19, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(52, (uint64_t)irq20, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(53, (uint64_t)irq21, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(54, (uint64_t)irq22, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(55, (uint64_t)irq22, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(56, (uint64_t)irq23, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(57, (uint64_t)irq24, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(58, (uint64_t)irq25, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(59, (uint64_t)irq26, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(60, (uint64_t)irq27, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(61, (uint64_t)irq28, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(62, (uint64_t)irq29, 0x08, 0x8F);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(63, (uint64_t)irq31, 0x08, 0x8F);

    interruptDescriptorTable->setInterruptDescriptorTableEntry(64, (uint64_t)apirq32, 0x08, 0x8E); // This is for the AP
    interruptDescriptorTable->setInterruptDescriptorTableEntry(65, (uint64_t)apirq33, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(66, (uint64_t)apirq34, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(67, (uint64_t)irq35, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(68, (uint64_t)irq36, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(69, (uint64_t)irq37, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(70, (uint64_t)irq38, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(71, (uint64_t)irq39, 0x08, 0x8E);
    interruptDescriptorTable->setInterruptDescriptorTableEntry(72, (uint64_t)irq40, 0x08, 0x8E);

    interruptDescriptorTable->setInterruptDescriptorTableEntry(255, (uint64_t)isr255, 0x08, 0x8E);

    interruptDescriptorTablePointer = interruptDescriptorTable->getInterruptDescriptorTablePointer();
    idtInit();
    irqClearMask(IRQ2-IRQ0);
    irqClearMask(IRQ7-IRQ0);

}


InterruptManager::InterruptManager()
{
    interruptDescriptorTable = new InterruptDescriptorTable();
    Utils::memset((uint64_t *) interruptHandlers, 0, IDT_SIZE);
    initialize();

}

bool InterruptManager::registerInterrupt(uint8_t int_no,InterruptHandler * interruptHandler)
{


    disable();
    interruptHandlers[int_no] = interruptHandler;
    if ( int_no >= IRQ0)
        irqClearMask(int_no-IRQ0);
    enable();
    return true;
}

bool InterruptManager::serviceInterrupt (struct interrupted_context * ic)
{
    if ( interruptHandlers[ic->intNo] != NULL)
    {
        interruptHandlers[ic->intNo]->fire(ic);
        return true;
    }
    else return false;

}
InterruptManager::~InterruptManager()
{

}

And here is the interrupt handler abstract class

Code: Select all

class InterruptHandler
{
    protected:
        interrupted_context * ic;
        CoreManager * coreManager;

    public:
        InterruptHandler(CoreManager * _coreManager = NULL);
        void setCoreManager (CoreManager * _coreManager);
        virtual void fire (struct interrupted_context * _ic);
        void APICEOI ();
        ~InterruptHandler();
};

InterruptHandler::InterruptHandler(CoreManager * _coreManager)
{

    coreManager = _coreManager;
}
void InterruptHandler::setCoreManager (CoreManager * _coreManager)
{
    coreManager = _coreManager;
}

void InterruptHandler::fire (struct interrupted_context * _ic)
{
    ic = _ic;
}
void InterruptHandler::APICEOI ()
{
    Utils::writeLocalAPIC(LAPIC_EOI,0b00000000000000000000000000000000);
    sfence();
}
InterruptHandler::~InterruptHandler()
{
}
Now, the PIT, the RTC, and the AP PIT(at 64) interrupt handlers inherit from it and overload the fire method. I will present the fire method for each.

Here is RTC fire method.

Code: Select all

void RTCTimer::fire (struct interrupted_context * ic)
{
    v->setPosition(50,23);
    v->putString("RTC Seconds: " ,COLOR_RED,COLOR_BLACK);
    v->putDecimal( seconds,COLOR_RED,COLOR_BLACK);
    v->putString("\n" ,COLOR_RED,COLOR_BLACK);

    if ( ic != NULL)
    {
        ticks++;
        if ( ticks == 0  ) save_ticks = 0;
        if ( ticks - save_ticks == 1024)
        {
            save_ticks = ticks;
            seconds ++;
            global_seconds++;
        }
    }
    Ports::outportb(0x70, 0x0C);	// select register C
    Ports::inportb(0x71);		// just throw away contents

}

Here is the AP PIT fire method

Code: Select all

oid APPITScheduler::fire (struct interrupted_context * ic)
{
	uint32_t core_id = Utils::getAPICId();
	ticks++;
	video->setPosition(0,17+core_id);
	video->putString("Tick: ",COLOR_BLUE,COLOR_WHITE);
	video->putDecimal(ticks,COLOR_BLUE,COLOR_WHITE);
	video->putString(", cpuid: ",COLOR_BLUE,COLOR_WHITE);
	video->putHexa(core_id,COLOR_BLUE,COLOR_WHITE);
	APICEOI();
}
And here is the PIT fire method

Code: Select all

void PITScheduler::fire (struct interrupted_context * ic)
{
    ticks++;
    if (ic == NULL) return ;
    if ( ticks % 2 == 0 && coreManager != NULL && coreManager->getCoreCount() > 1 && coreManager->isAllTouched())
    {
        uint16_t core_id = (ipi_count % (coreManager->getCoreCount()-1)) +1;
        coreManager->sendIPI(core_id,coreManager->getTimerIRQ(core_id)); // If I comment out this the RTC keeps on firing else it will fire for a while until the first IPI is intiated and then it will stop for ever
        ipi_count ++;
    }

}
For convienence here is the sendIPI methods

Code: Select all

void CoreManager::sendIPI (uint16_t _core_id, uint8_t irq)
{
    if ( _core_id < core_count)
        cores[_core_id]->sendIPI(irq);
}

void Core::sendIPI (uint8_t irq)
{
        uint32_t _core_id = core_id << 24;
        Utils::writeLocalAPIC(LAPIC_ICR1, _core_id);
        Utils::writeLocalAPIC(LAPIC_ICR0, 0b00000000000000000100000000000000| irq);
        sfence();
}

Now lets look at the interrupt handler routine that call the above.

Code: Select all


extern "C" void idt_handler(struct interrupted_context * ic)
{
    uint32_t core_id  = Utils::getAPICId();
    if (ic->intNo >= 40 && ic->intNo <= 47)
    {
        Ports::outportb(PIC2_COMMAND, 0x20);
    }

    if (ic->intNo >= 32 ) Ports::outportb(PIC1_COMMAND, 0x20);

    if (interruptManagers[core_id]->serviceInterrupt(ic) )
    {
        return;
    }
    else
    {
        video.setPosition(30,10);
        if ( ic->intNo < IRQ0)
        {
		video.putString(exception_messages[ic->intNo],COLOR_RED,COLOR_LIGHT_BROWN);
		video.putString("[",COLOR_RED,COLOR_LIGHT_BROWN);
		video.putHexa(ic->intNo,COLOR_RED,COLOR_LIGHT_BROWN);
		video.putString("]\n",COLOR_RED,COLOR_LIGHT_BROWN);
		uint64_t cr2;
		asm volatile("mov %%cr2, %0": "=r"(cr2));
		video.setPosition(30,11);
		video.putString("Fault Address:",COLOR_RED,COLOR_LIGHT_BROWN);
		video.putHexa(cr2,COLOR_RED,COLOR_LIGHT_BROWN);
		video.putString("\n",COLOR_RED,COLOR_LIGHT_BROWN);
		video.setPosition(30,12);
		video.putString("Fault Instruction Address:",COLOR_RED,COLOR_LIGHT_BROWN);
		video.putHexa(ic->return_address,COLOR_RED,COLOR_LIGHT_BROWN);
		video.putString("\n",COLOR_RED,COLOR_LIGHT_BROWN);
        }
        else
        {
                //Unhandled exception
        }
    }
}


Now if we look at the fire method of the PITScheduler, every 2 times it fires it issues an IPI to one of the processors.

Please find attached an image with the running console when I run this with and without the IPI. Notice the difference which is in the screen shot with IPI enabled it stops at 6 seconds.


Thanks
Karim.
Attachments
qemu_without_ipi.png
qemu_with_ipi.png
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: RTC interrupts stop after my first IPI

Post by Combuster »

I need 4GB for my kernel to work.
I need 4MB. Why is yours a factor 1000 less space-efficient in the first place? And how does that size even relate to problems with interrupts?
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
kemosparc
Member
Member
Posts: 207
Joined: Tue Oct 29, 2013 1:13 pm

Re: RTC interrupts stop after my first IPI

Post by kemosparc »

Hi,

Yours need 4 MB!! The only thing that I can think of is that you are a genius I am not; if I were you, I would have been walking in the sky right now.

The size does not relate to the interrupt problem.

When I try to map address 0xFEE00000 (APIC headers) in Bochs it just crashes with RAM less than 4GG, so I was trying to make it work on 4 GB first before investigating my problem to make sure that there is nothing else related to Bochs being crached with memory less than 4GB; basically I was trying to have a configuration environment on Bochs identical to that I am testing with on Qemu and where the problem occurs.

Thanks,
Karim.
madanra
Member
Member
Posts: 149
Joined: Mon Sep 07, 2009 12:01 pm

Re: RTC interrupts stop after my first IPI

Post by madanra »

If the APIC headers are actually at 0xFEE00000, you should not need 4GB RAM to access them.
kemosparc
Member
Member
Posts: 207
Joined: Tue Oct 29, 2013 1:13 pm

Re: RTC interrupts stop after my first IPI

Post by kemosparc »

Unless there is something I don't understand:

0xFEE00000 = 4,276,092,928 Bytes = 4,175,872 KBytes = 4078 MB ~ 4 GB

Thanks,
Karim.
Nable
Member
Member
Posts: 453
Joined: Tue Nov 08, 2011 11:35 am

Re: RTC interrupts stop after my first IPI

Post by Nable »

kemosparc wrote:Unless there is something I don't understand:

0xFEE00000 = 4,276,092,928 Bytes = 4,175,872 KBytes = 4078 MB ~ 4 GB

Thanks,
Karim.
This area isn't "headers", it's MMIO (memory-mapped input/output) - there is no RAM at these addresses and read/write requests are forwarded to some devices instead of RAM. Even if you have 4G RAM, it won't be mapped at such addresses, instead it would be either inaccessible or mapped to higher addresses.
kemosparc
Member
Member
Posts: 207
Joined: Tue Oct 29, 2013 1:13 pm

Re: RTC interrupts stop after my first IPI

Post by kemosparc »

Okay,

I got Bochs to work, I adjusted a couple of things in my memory setting to make it work on less than 4G.

Nevertheless, there are some problems with the APCI, that appears in Bochs and not in Qemu.

I will try to work on them one by one, here is the first one:

Bochs keeps on throwing this message in the terminal

Code: Select all

warning: misaligned APIC access. addr=0x0000fee00023
I think my problem is very close to the one in this post http://f.osdev.org/viewtopic.php?t=24961

My function that reads from the APIC MMIO looks like this:

Code: Select all

uint32_t Utils::readLocalAPIC(uint64_t reg)
{
    return (uint32_t)(*(uint32_t* volatile)((uint64_t) reg));
}
And I call it like this to get the core id (This is where the problem occurs):

Code: Select all

        uint32_t cpuid = Utils::readLocalAPIC(LAPIC_REG);
LAPIC_REG is 0x0000fee00020, but for some reason the compiler adds to it 3.

Here is the code from the objdump:

Code: Select all

   104d1:       0f b6 04 25 23 00 10    movzbl 0x100023,%eax
   104d8:       00 
I map 0x0000fee00000 to 0x100000, and it should be 0x100020

Kindly if any one knows what is going on please let me know.

Thanks
Karim.
kemosparc
Member
Member
Posts: 207
Joined: Tue Oct 29, 2013 1:13 pm

Re: RTC interrupts stop after my first IPI

Post by kemosparc »

Thanks a lot. BUt I don't know where your post has gone???
Your first point fixed my problem.

Now, Back to my original problem, but now I am using Bochs.

Why RTC stops as soon as I send IPIs.

Note that on Bochs RTC stops as soon as I sent the INIT IPI.

How can I tell Bochs to generate more data about the interrupts?

Thanks,
Karim.
Nable
Member
Member
Posts: 453
Joined: Tue Nov 08, 2011 11:35 am

Re: RTC interrupts stop after my first IPI

Post by Nable »

Sorry! Soon after that post, I've suddenly understood that I'm unsure whether "volatile uint32_t *" and "uint32_t volatile *" are the same construction, so I've decided to quickly test it before leaving the reply. Here's the text of my "deleted" post:
Nable wrote:
kemosparc wrote:

Code: Select all

uint32_t Utils::readLocalAPIC(uint64_t reg)
{
    return (uint32_t)(*(uint32_t* volatile)((uint64_t) reg));
}
Where did you get such an example?
1. AFAIK, "uint32_t* volatile" should be "volatile uint32_t*" (or "uint32_t volatile *"), this may be the cause of your problem.
2. "(uint64_t) reg" is illogical - "reg" is already uint64_t.
3. "(uint32_t)" is also redundant.
4. IMHO, it's better to use uintptr_t for MMIO addresses instead of just uint64_t.
5. Note that MMIO addresses are physical and if you use paging, then you should use physical2virtual(LAPIC_ADDRESS) as a pointer instead of just LAPIC_ADDRESS.
Talking about Bochs. Did you compile it with debugging support? Command "info device <short-name-of-device>" shows you state of chosen device (e.g. pic). Command "info device" w/o further parameters shows list of devices that support that command. You can also configure logging of some components in "bochsrc", then you'll see messages that are printed via BX_ERROR/BX_DEBUG/BX_INFO macroses. You can also implement some additional logging and recompile Bochs (it's sometimes easier than learning all those configuration options).
Post Reply