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.