RTC interrupts stop after my first IPI
RTC interrupts stop after my first IPI
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.
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.
Re: RTC interrupts stop after my first IPI
Hi,
Cheers,
Brendan
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.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?
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.
Re: RTC interrupts stop after my first IPI
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.
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.
Re: RTC interrupts stop after my first IPI
Hi,
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
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).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.
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.
Re: RTC interrupts stop after my first IPI
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:
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.
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.
- xenos
- 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
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.
Re: RTC interrupts stop after my first IPI
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:
My interrupt handlers are based on a manager class and interrupt handler abstract class
And here is the interrupt handler abstract class
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.
Here is the AP PIT fire method
And here is the PIT fire method
For convienence here is the sendIPI methods
Now lets look at the interrupt handler routine that call the above.
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.
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()
{
}
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()
{
}
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();
}
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 ++;
}
}
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.
- Combuster
- 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
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?I need 4GB for my kernel to work.
Re: RTC interrupts stop after my first IPI
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.
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.
Re: RTC interrupts stop after my first IPI
If the APIC headers are actually at 0xFEE00000, you should not need 4GB RAM to access them.
Re: RTC interrupts stop after my first IPI
Unless there is something I don't understand:
0xFEE00000 = 4,276,092,928 Bytes = 4,175,872 KBytes = 4078 MB ~ 4 GB
Thanks,
Karim.
0xFEE00000 = 4,276,092,928 Bytes = 4,175,872 KBytes = 4078 MB ~ 4 GB
Thanks,
Karim.
Re: RTC interrupts stop after my first IPI
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 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.
Re: RTC interrupts stop after my first IPI
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
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:
And I call it like this to get the core id (This is where the problem occurs):
LAPIC_REG is 0x0000fee00020, but for some reason the compiler adds to it 3.
Here is the code from the objdump:
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.
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
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));
}
Code: Select all
uint32_t cpuid = Utils::readLocalAPIC(LAPIC_REG);
Here is the code from the objdump:
Code: Select all
104d1: 0f b6 04 25 23 00 10 movzbl 0x100023,%eax
104d8: 00
Kindly if any one knows what is going on please let me know.
Thanks
Karim.
Re: RTC interrupts stop after my first IPI
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.
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.
Re: RTC interrupts stop after my first IPI
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:
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).Nable wrote:Where did you get such an example?kemosparc wrote:Code: Select all
uint32_t Utils::readLocalAPIC(uint64_t reg) { return (uint32_t)(*(uint32_t* volatile)((uint64_t) reg)); }
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.