Пример #1
0
void iniz( u32 idt, u32 gdt )
{
  exIdt = idt;
  exGdt = gdt;

  inizVConsole();

  // Configuring PIT (programmable interval timer)
  // PIT Channel 0 - IRQ0 - scheduler
  INIT_PIT( PIT_CONFIG_CH0 | PIT_MODE3 | PIT_BIN | PIT_READ_LHB );
  SET_PIT( PIT_DIVIDER(20), PIT_CH0 );

  // Set 24-hour mode
  // Set binary data format
  wrcmos( rdcmos(CMOS_RTC_STATUSB) | 0x4 | 0x2, CMOS_RTC_STATUSB );

  // If battery is low...
  if( !(rdcmos(CMOS_RTC_STATUSD) & 0x80) )
    vsprint("warning: cmos battery is low\n");

  // Configuring PIC and interrupts
  setTrapGate( &onIRQ0, IRQ(0) );
  setTrapGate( &onIRQ1, IRQ(1) );
  SET_PIC_MASK( ~0x0300 );

  // Configuring scheduler
  inizTask( &xtask, TSS_ENTRY(0) );
  LTR( xtask.uid );
  currentTask = &xtask;
  currentTask->next = currentTask;
};
Пример #2
0
void ArchBoardSpecific::irq_handler()
{
  uint32* pic = (uint32*)PIC_BASE;
  if (IRQ(0))
    arch_swi_irq_handler();
  if (IRQ(22))
    uart0_irq_handler();
  if (IRQ(26))
    timer0_irq_handler();
  // 6-10 and 22-28 not implemented
}
Пример #3
0
Error ProcessCtlHandler(ProcessID procID, ProcessOperation action, Address addr)
{
    Process *proc = ZERO;
    ProcessInfo *info = (ProcessInfo *) addr;
    ProcessManager *procs = Kernel::instance->getProcessManager();

    DEBUG("#" << procs->current()->getID() << " " << action << " -> " << procID << " (" << addr << ")");

    // TODO: Verify memory address

    // Does the target process exist?
    if(action != GetPID && action != Spawn)
    {
        if (procID == SELF)
            proc = procs->current();
        else if (!(proc = procs->get(procID)))
            return API::NotFound;
    }
    // Handle request
    switch (action)
    {
    case Spawn:
        proc = procs->create(addr);
        return proc->getID();
    
    case KillPID:
            procs->remove(proc);
        break;

    case GetPID:
        return procs->current()->getID();

    case Schedule:
        procs->schedule();
        break;

    case Resume:
        proc->setState(Process::Ready);
        break;

    case WatchIRQ:
        Kernel::instance->hookInterrupt(IRQ(addr), (InterruptHandler *)interruptNotify, (ulong)proc);
        Kernel::instance->enableIRQ(addr, true);
        break;
    
    case InfoPID:
        info->id    = proc->getID();
        info->state = proc->getState();
        info->userStack     = proc->getUserStack();
        info->kernelStack   = proc->getKernelStack();
        info->pageDirectory = proc->getPageDirectory();
        break;
        
    case SetStack:
        proc->setUserStack(addr);
        break;
    }
    return API::Success;
}
Пример #4
0
Файл: int.c Проект: lutoma/xelix
/* This one get's called from the architecture-specific interrupt
 * handlers, which do fiddling like EOIs (i386).
 */
isf_t* __attribute__((fastcall)) interrupts_callback(uint32_t intr, isf_t* regs) {
	struct interrupt_reg reg = interrupt_handlers[intr];
	task_t* task = scheduler_get_current();

	#ifdef INTERRUPTS_DEBUG
	debug("state before:\n");
	dump_isf(LOG_DEBUG, regs);
	#endif

	if(reg.handler) {
		if(reg.can_reent) {
			interrupts_enable();
		}
		reg.handler(regs);
	}

	#ifdef ENABLE_PICOTCP
	if(intr == IRQ(0)) {
		net_tick();
	}
	#endif

	// Run scheduler every 100th tick, or when task yields
	if((intr == IRQ(0) && !(timer_get_tick() % 100)) || (task && task->interrupt_yield)) {
		if((task && task->interrupt_yield)) {
			task->interrupt_yield = false;
		}

		task_t* new_task = scheduler_select(regs);
		if(new_task && new_task->state) {
			#ifdef INTERRUPTS_DEBUG
			debug("state after (task selection):\n");
			dump_isf(LOG_DEBUG, new_task->state);
			#endif

			gdt_set_tss(new_task->kernel_stack + PAGE_SIZE);
			return new_task->state;
		}
	}

	#ifdef INTERRUPTS_DEBUG
	debug("state after:\n");
	dump_isf(LOG_DEBUG, regs);
	#endif
	return regs;
}
Пример #5
0
static int
atpic_vector(struct intsrc *isrc)
{
	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
	struct atpic *ap = (struct atpic *)isrc->is_pic;

	return (IRQ(ap, ai));
}
Пример #6
0
int f () {
  /* Handle IRQ0 = PIT timer. */
  register_interrupt_handler(IRQ(0), &h, (void*)0xdeadbeef);

  __asm volatile("sti");

  for (;;);
  
  return 0;
}
Пример #7
0
void X86Kernel::interrupt(CPUState *state, ulong param)
{
    /* End of Interrupt to slave. */
    if (IRQ(state->vector) >= 8)
    {
        outb(PIC2_CMD, PIC_EOI);
    }
    /* End of Interrupt to master. */
    outb(PIC1_CMD, PIC_EOI);
}
Пример #8
0
void CPU::Exec()
{
	uint8_t opCode = GetOPCode();
	_instAddrMode = _addrMode[opCode];
	_operand = FetchOperand();
	(this->*_opTable[opCode])();
	
	if(_prevRunIrq) {
		IRQ();
	}
}
Пример #9
0
int ProcessCtlHandler(ProcessID procID, ProcessOperation action, Address addr)
{
    ArchProcess *proc = ZERO;
    ProcessInfo *info = (ProcessInfo *) addr;

    /* Verify memory address. */
    if (action == InfoPID) {
        if (!memory->access(scheduler->current(), addr, sizeof(ProcessInfo))) {
            return EFAULT;
        }
    }
    
    /* Does the target process exist? */
    if(action != GetPID && action != Spawn && !(proc = Process::byID(procID))) {
        return ESRCH;
    }
    
    /* Handle request. */
    switch (action) {
        case Spawn:
            proc = new ArchProcess(addr);
            return proc->getID();
        case KillPID:
            delete proc;
            break;
        case GetPID:
            return scheduler->current()->getID();
        case Schedule:
            scheduler->executeNext();
            break;
        case Resume:
            proc->setState(Ready);
            scheduler->enqueue(proc);
            break;
        case AllowIO:
            proc->IOPort(addr, true);
            break;
        case WatchIRQ:
            kernel->hookInterrupt(IRQ(addr),
            (InterruptHandler *)interruptNotify, (ulong)proc);
            kernel->enableIRQ(addr, true);
            break;
        case InfoPID:
            info->id    = proc->getID();
            info->state = proc->getState();
            info->stack = proc->getStack();
            info->pageDirectory = proc->getPageDirectory();
            break;
        case SetStack:
            proc->setStack(addr);
            break;
    }
    return 0;
}
Пример #10
0
void tty_keyboard_init() {
	flush();

	// Reset
	send(0xF6);

	// Repeat rate
	send(0xF3);
	send(0);

	send(0xF4);
	flush();
	interrupts_register(IRQ(1), &intr_handler, false);
}
Пример #11
0
// Initialize everything that needs to be set up.
void Init(void) {
  // Enable the PIT clock.
  SIM_SCGC3 |= SIM_SCGC3_ADC1_MASK;
  SIM_SCGC6 |= SIM_SCGC6_PIT_MASK | SIM_SCGC6_ADC0_MASK;

  // Turn on PIT.
  PIT_MCR = 0x00;
  // Timer 1
  PIT_LDVAL1 = mcg_clk_hz /* 60;*/>> 2; // setup timer 1 for 4Hz.
  PIT_TCTRL1 = PIT_TCTRL_TIE_MASK; // enable Timer 1 interrupts
  PIT_TCTRL1 |= PIT_TCTRL_TEN_MASK; // start Timer 1

  // Enable interrupts.
  enable_irq(IRQ(INT_PIT1));
  EnableInterrupts
}
Пример #12
0
static void irq_notify(void)
{
    Context* context = get_context();

    uint8_t irq = IRQ(context->num);
    if (!irqThread[irq]) return;

    Thread* receiver = thread_get(irqThread[irq]);
    if (receiver->state == WAIT_RECEIVING && receiver->waitingFor == 0
                                          && receiver->waitingIrq == irq)
    {
        irqPending[irq] = false;
        scheduler_unblock(receiver);
    }
    else
        irqPending[irq] = true;
}
Пример #13
0
int RK05_Service()
{
	int irq = 0;

	if (rk05.rdy_cnt)
	{
		--rk05.rdy_cnt;
		if (0 == rk05.rdy_cnt)
		{
			rk05.rkcs |= RKCS_RDY_BIT;
			irq = 1;
		}
	}

	if (irq && (rk05.rkcs & RKCS_IDE_BIT))
	{
		IRQ(0220);
	}

	return 0;
}
Пример #14
0
void imx233_timrot_setup(unsigned timer_nr, bool reload, unsigned count,
    unsigned src, unsigned prescale, bool polarity, imx233_timer_fn_t fn)
{
    int oldstatus = disable_interrupt_save(IRQ_FIQ_STATUS);
    /* only enable interrupt if function is set */
    bool irq = fn != NULL;
    timer_fns[timer_nr] = fn;

    /* make sure we start from stop state */
    HW_TIMROT_TIMCTRLn(timer_nr) = BF_OR2(TIMROT_TIMCTRLn,
        SELECT(BV_TIMROT_TIMCTRLn_SELECT__NEVER_TICK), UPDATE(1));
    /* write count and take effect immediately with UPDATE
     * manual says count-1 for reload timers */
    HW_TIMROT_TIMCOUNTn(timer_nr) = reload ? count - 1 : count;
    /* start timer */
    HW_TIMROT_TIMCTRLn(timer_nr) = BF_OR6(TIMROT_TIMCTRLn, SELECT(src),
        PRESCALE(prescale), POLARITY(polarity), RELOAD(reload), IRQ(irq),
        IRQ_EN(irq));
    imx233_icoll_enable_interrupt(INT_SRC_TIMER(timer_nr), irq);

    restore_interrupt(oldstatus);
}
Пример #15
0
// Initialize the PIT
void timer_init() {
	// preemptability setting here also affects scheduler, so leave set to false
	interrupts_register(IRQ(0), &timer_callback, false);
	rate = PIT_RATE;

	// The value we send to the PIT is the value to divide it's input clock
	// (1193180 Hz) by, to get our required frequency. Important to note is
	// that the divisor must be small enough to fit into 16-bits.
	uint32_t divisor = 1193180 / rate;
	// Send the command byte.
	outb(0x43, 0x36);

	// Divisor has to be sent byte-wise, so split here into upper/lower bytes.
	uint8_t l = (uint8_t)(divisor & 0xFF);
	uint8_t h = (uint8_t)( (divisor>>8) & 0xFF );

	// Send the frequency divisor.
	outb(0x40, l);
	outb(0x40, h);

	log(LOG_DEBUG, "pit: Timer frequency %d\n", rate);
}
Пример #16
0
void ArchBoardSpecific::irq_handler()
{
  uint32* pic = (uint32*)PIC_BASE;
  if (IRQ(0))
    arch_swi_irq_handler();
  if (IRQ(1))
    uart0_irq_handler();
  if (IRQ(2))
    arch_uart1_irq_handler();
  if (IRQ(3))
    keyboard_irq_handler();
  if (IRQ(4))
    arch_mouse_irq_handler();
  if (IRQ(5))
    timer0_irq_handler();
  // 6-10 and 22-28 not implemented
}
Пример #17
0
IntelKernel::IntelKernel(Memory::Range kernel, Memory::Range memory)
    : Kernel(kernel, memory)
{
    // Set PIT interrupt frequency to 250 hertz
    m_pit.setFrequency(250);

    IntelMap map;

    /* ICW1: Initialize PIC's (Edge triggered, Cascade) */
    IO::outb(PIC1_CMD, 0x11);
    IO::outb(PIC2_CMD, 0x11);
    
    /* ICW2: Remap IRQ's to interrupts 32-47. */
    IO::outb(PIC1_DATA, PIC_IRQ_BASE);
    IO::outb(PIC2_DATA, PIC_IRQ_BASE + 8);

    /* ICW3: PIC2 is connected to PIC1 via IRQ2. */
    IO::outb(PIC1_DATA, 0x04);
    IO::outb(PIC2_DATA, 0x02);

    /* ICW4: 8086 mode, fully nested, not buffered, no implicit EOI. */
    IO::outb(PIC1_DATA, 0x01);
    IO::outb(PIC2_DATA, 0x01);

    /* OCW1: Disable all IRQ's for now. */
    IO::outb(PIC1_DATA, 0xff);
    IO::outb(PIC2_DATA, 0xff);
    
    /* Make sure to enable PIC2 and the PIT interrupt */
    enableIRQ(2, true);
    enableIRQ(m_pit.getInterruptVector(), true);

    // Install interruptRun() callback
    interruptRun = ::executeInterrupt;

    /* Setup exception handlers. */
    for (int i = 0; i < 17; i++)
    {
        hookInterrupt(i, exception, 0);
    }
    /* Setup IRQ handlers. */
    for (int i = 17; i < 256; i++)
    {
        /* Trap gate. */
        if (i == 0x90)
            hookInterrupt(0x90, trap, 0);

        /* Hardware Interrupt. */
        else
            hookInterrupt(i, interrupt, 0);
    }
    /* Install PIT (i8253) IRQ handler. */
    hookInterrupt(IRQ(m_pit.getInterruptVector()), clocktick, 0);

    // Initialize TSS Segment
    gdt[KERNEL_TSS].limitLow    = sizeof(TSS) + (0xfff / 8);
    gdt[KERNEL_TSS].baseLow     = ((Address) &kernelTss) & 0xffff;
    gdt[KERNEL_TSS].baseMid     = (((Address) &kernelTss) >> 16) & 0xff;
    gdt[KERNEL_TSS].type        = 9;
    gdt[KERNEL_TSS].privilege   = 0;
    gdt[KERNEL_TSS].present     = 1;
    gdt[KERNEL_TSS].limitHigh   = 0;
    gdt[KERNEL_TSS].granularity = 8;
    gdt[KERNEL_TSS].baseHigh    = (((Address) &kernelTss) >> 24) & 0xff;

    // Fill the Task State Segment (TSS).
    MemoryBlock::set(&kernelTss, 0, sizeof(TSS));
    kernelTss.ss0    = KERNEL_DS_SEL;
    kernelTss.esp0   = 0;
    kernelTss.bitmap = sizeof(TSS);
    ltr(KERNEL_TSS_SEL);
}
Пример #18
0
void glInternalFlush(u32 target) {
	u32 i;
	u32 param_base = REGS32(0x8020) & 0x007FFFFF;
	u32 background = (REGS32(0x808C) & 0x00FFFFF8) >> 1;
	u32 address = (param_base + background) & 0x007FFFFF;

	flushPrim();
	NewStripList();

	BACKGROUND((u32*)&VRAM[address]);

	flushPrim();
	NewStripList();

	glClearColor((float)REGS[0x8042] / 255.0f,
				 (float)REGS[0x8041] / 255.0f,
				 (float)REGS[0x8040] / 255.0f,
				 (float)REGS[0x8043] / 255.0f);
	glDepthMask(GL_TRUE);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	if (cfg.ListSorting) {
		qsort((void*)objList, objCount, sizeof(OBJECT), comp_func);
//		qsort((void*)objList,objCount,sizeof(OBJECT),listtypesort_func);
//		qsort((void*)objList,objCount,sizeof(OBJECT),transsort_func);
//		qsort((void*)objList,objCount,sizeof(OBJECT),punchsort_func);
	}

	glPushMatrix();

	switch (target) {
	case RENDER_TARGET_FRAMEBUFFER:
		glViewport(0, 0, 640, 480);
		glTranslatef(0.0f, 0.0f, -(float)RENDER_VIEW_DISTANCE);
		break;
	case RENDER_TARGET_TEXTURE:
	{
		glViewport(0, 0, 640, (REGS16(0x806E) - REGS16(0x806c) + 1));
		glScalef(1.0f, -1.0f, 1.0f);
		glTranslatef(0.0f, -480.0f, -(float)RENDER_VIEW_DISTANCE);
		break;
	}
	}

//	DEMUL_printf(">render scene (objCount=%d)\n",objCount);

	for (i = 0; i < objCount; i++) {
		OBJECT *obj = &objList[i];
		vCount = obj->vCount;

		if (vCount) {
			polygon = obj->polygon;

//			DEMUL_printf(">object %3d, dist = %6f, listtype = %d, pcw = %08X, isp = %08X, tsp = %08X, tcw = %08X\n",i,obj->midZ, obj->polygon.pcw.listtype, obj->polygon.pcw.all, obj->polygon.isp.all, obj->polygon.tsp.all, obj->polygon.tcw.all);

			if (polygon.tsp.usealpha && cfg.AlphaZWriteDisable)
				polygon.isp.zwritedis = 1;

			SetupShadeMode();
			SetupCullMode();
			SetupZBuffer();
			if (cfg.Wireframe) {
				glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
			} else {
				SetupAlphaTest();
				SetupAlphaBlend();
				SetupTexture();
				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
			}

			glDrawElements(GL_TRIANGLES, vCount, GL_UNSIGNED_INT, &pIndex[obj->vIndex]);
		}
	}
	glPopMatrix();

//	ProfileFinish(0);

	IRQ(0x0002);

	switch (target) {
	case RENDER_TARGET_FRAMEBUFFER:
		SwapBuffers(hdc);
		break;
	case RENDER_TARGET_TEXTURE:
	{
		u32 tw = REGS32(0x804C) << 2;
		u32 th = 512;
		glReadBuffer(GL_BACK);
		glBindTexture(GL_TEXTURE_2D, backbufname);
		glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, tw, th, 0);
		isFramebufferRendered = 1;
		TextureAddress = REGS32(0x8060) & 0x007FFFFF;
		break;
	}
	}

//	DEMUL_printf(">render end\n");
//	DEMUL_printf(">frame summary (maxz=%f,minz=%f)\n",maxz,minz);

	maxz = -10000000.0f;
	minz = 10000000.0f;
	objCount = 0;
	vIndex = 0;
	vCount = 0;
	vVertex = 0;
}
Пример #19
0
X86Kernel::X86Kernel() : Kernel(), ticks(0)
{
    /* ICW1: Initialize PIC's (Edge triggered, Cascade) */
    outb(PIC1_CMD, 0x11);
    outb(PIC2_CMD, 0x11);
    
    /* ICW2: Remap IRQ's to interrupts 32-47. */
    outb(PIC1_DATA, PIC_IRQ_BASE);
    outb(PIC2_DATA, PIC_IRQ_BASE + 8);

    /* ICW3: PIC2 is connected to PIC1 via IRQ2. */
    outb(PIC1_DATA, 0x04);
    outb(PIC2_DATA, 0x02);

    /* ICW4: 8086 mode, fully nested, not buffered, no implicit EOI. */
    outb(PIC1_DATA, 0x01);
    outb(PIC2_DATA, 0x01);

    /* OCW1: Disable all IRQ's for now. */
    outb(PIC1_DATA, 0xff);
    outb(PIC2_DATA, 0xff);

    /* Let the i8253 timer run continuously (square wave). */
    outb(PIT_CMD, 0x36);
    outb(PIT_CHAN0, PIT_DIVISOR & 0xff);
    outb(PIT_CHAN0, PIT_DIVISOR >> 8);
    
    /* Make sure to enable PIC2 and the i8253. */
    enableIRQ(2, true);
    enableIRQ(0, true);

    /* Setup exception handlers. */
    for (int i = 0; i < 17; i++)
    {
        hookInterrupt(i, exception, 0);
    }
    /* Setup IRQ handlers. */
    for (int i = 17; i < 256; i++)
    {
        /* Trap gate. */
        if (i == 0x90)
            hookInterrupt(0x90, trap, 0);

        /* Hardware Interrupt. */
        else
            hookInterrupt(i, interrupt, 0);
    }
    /* Install PIT (i8253) IRQ handler. */
    hookInterrupt(IRQ(0), clocktick, 0);

    /* Initialize TSS Segment. */
    gdt[USER_TSS].limitLow    = sizeof(TSS) + (0xfff / 8);
    gdt[USER_TSS].baseLow     = ((Address) &kernelTss) & 0xffff;
    gdt[USER_TSS].baseMid     = (((Address) &kernelTss) >> 16) & 0xff;
    gdt[USER_TSS].type        = 9;
    gdt[USER_TSS].privilege  = 0;
    gdt[USER_TSS].present     = 1;
    gdt[USER_TSS].limitHigh   = 0;
    gdt[USER_TSS].granularity = 8;
    gdt[USER_TSS].baseHigh    = (((Address) &kernelTss) >> 24) & 0xff;

    /* Let TSS point to I/O bitmap page. */
    kernelTss.bitmap = PAGESIZE << 16;

    /* Load Task State Register. */
    ltr(USER_TSS_SEL);
}
Пример #20
0
void ArchBoardSpecific::irq_handler()
{
  uint32* pic = (uint32*)PIC_BASE;
  if (IRQ(0))
    timer0_irq_handler();
}
Пример #21
0
Error ProcessCtlHandler(ProcessID procID, ProcessOperation action, Address addr)
{
#ifdef __i386__
    IntelProcess *proc = ZERO;
    Memory *memory = Kernel::instance->getMemory();
    ProcessInfo *info = (ProcessInfo *) addr;
    ProcessManager *procs = Kernel::instance->getProcessManager();

    DEBUG("#" << procs->current()->getID() << " " << action << " -> " << procID << " (" << addr << ")");

    /* Verify memory address. */
    if (action == InfoPID)
    {
	if (!memory->access(procs->current(), addr, sizeof(ProcessInfo)))
	{
	    return API::AccessViolation;
	}
    }
    /* Does the target process exist? */
    if(action != GetPID && action != Spawn)
    {
        if (procID == SELF)
            proc = (IntelProcess *) procs->current();
        else if (!(proc = (IntelProcess *)procs->get(procID)))
	    return API::NotFound;
    }
    /* Handle request. */
    switch (action)
    {
	case Spawn:
	    proc = (IntelProcess *) procs->create(addr);
	    return proc->getID();
	
	case KillPID:
            procs->remove(proc);
	    break;

	case GetPID:
	    return procs->current()->getID();

	case Schedule:
            procs->schedule();
	    break;

	case Resume:
	    proc->setState(Process::Ready);
	    break;
	
	case AllowIO:
            return API::InvalidArgument;
	    //proc->IOPort(addr, true);
	    //break;
	
	case WatchIRQ:
	    Kernel::instance->hookInterrupt(IRQ(addr),
		(InterruptHandler *)interruptNotify, (ulong)proc);
	    Kernel::instance->enableIRQ(addr, true);
	    break;
	
	case InfoPID:
	    info->id    = proc->getID();
	    info->state = proc->getState();
	    info->stack = proc->getStack();
	    info->pageDirectory = proc->getPageDirectory();
	    break;
	    
	case SetStack:
	    proc->setStack(addr);
	    break;
    }
#endif
    return API::Success;
}
Пример #22
0
	else
		parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0;

	clk->parent = parent;
}

static struct dw_dma_platform_data dw_dmac0_data = {
	.nr_channels	= 3,
	.block_size	= 4095U,
	.nr_masters	= 2,
	.data_width	= { 2, 2, 0, 0 },
};

static struct resource dw_dmac0_resource[] = {
	PBMEM(0xff200000),
	IRQ(2),
};
DEFINE_DEV_DATA(dw_dmac, 0);
DEV_CLK(hclk, dw_dmac0, hsb, 10);

/* --------------------------------------------------------------------
 *  System peripherals
 * -------------------------------------------------------------------- */
static struct resource at32_pm0_resource[] = {
	{
		.start	= 0xfff00000,
		.end	= 0xfff0007f,
		.flags	= IORESOURCE_MEM,
	},
	IRQ(20),
};
Пример #23
0
IntelKernel::IntelKernel(Memory::Range kernel, Memory::Range memory)
    : Kernel(kernel, memory)
{
    Arch::Memory mem;

    /* ICW1: Initialize PIC's (Edge triggered, Cascade) */
    IO::outb(PIC1_CMD, 0x11);
    IO::outb(PIC2_CMD, 0x11);
    
    /* ICW2: Remap IRQ's to interrupts 32-47. */
    IO::outb(PIC1_DATA, PIC_IRQ_BASE);
    IO::outb(PIC2_DATA, PIC_IRQ_BASE + 8);

    /* ICW3: PIC2 is connected to PIC1 via IRQ2. */
    IO::outb(PIC1_DATA, 0x04);
    IO::outb(PIC2_DATA, 0x02);

    /* ICW4: 8086 mode, fully nested, not buffered, no implicit EOI. */
    IO::outb(PIC1_DATA, 0x01);
    IO::outb(PIC2_DATA, 0x01);

    /* OCW1: Disable all IRQ's for now. */
    IO::outb(PIC1_DATA, 0xff);
    IO::outb(PIC2_DATA, 0xff);

    /* Let the i8253 timer run continuously (square wave). */
    IO::outb(PIT_CMD, 0x36);
    IO::outb(PIT_CHAN0, PIT_DIVISOR & 0xff);
    IO::outb(PIT_CHAN0, PIT_DIVISOR >> 8);
    
    /* Make sure to enable PIC2 and the i8253. */
    enableIRQ(2, true);
    enableIRQ(0, true);

    // Install interruptRun() callback
    interruptRun = ::executeInterrupt;

    /* Setup exception handlers. */
    for (int i = 0; i < 17; i++)
    {
        hookInterrupt(i, exception, 0);
    }
    /* Setup IRQ handlers. */
    for (int i = 17; i < 256; i++)
    {
        /* Trap gate. */
        if (i == 0x90)
            hookInterrupt(0x90, trap, 0);

        /* Hardware Interrupt. */
        else
            hookInterrupt(i, interrupt, 0);
    }
    /* Install PIT (i8253) IRQ handler. */
    hookInterrupt(IRQ(0), clocktick, 0);

    // Initialize TSS Segment
    gdt[KERNEL_TSS].limitLow    = sizeof(TSS) + (0xfff / 8);
    gdt[KERNEL_TSS].baseLow     = ((Address) &kernelTss) & 0xffff;
    gdt[KERNEL_TSS].baseMid     = (((Address) &kernelTss) >> 16) & 0xff;
    gdt[KERNEL_TSS].type        = 9;
    gdt[KERNEL_TSS].privilege   = 0;
    gdt[KERNEL_TSS].present     = 1;
    gdt[KERNEL_TSS].limitHigh   = 0;
    gdt[KERNEL_TSS].granularity = 8;
    gdt[KERNEL_TSS].baseHigh    = (((Address) &kernelTss) >> 24) & 0xff;

    // Fill the Task State Segment (TSS).
    MemoryBlock::set(&kernelTss, 0, sizeof(TSS));
    kernelTss.esp0   = mem.range(Memory::KernelStack).virt + mem.range(Memory::KernelStack).size;
    kernelTss.ss0    = KERNEL_DS_SEL;
    kernelTss.bitmap = sizeof(TSS);

    // Load Task State Register
    ltr(KERNEL_TSS_SEL);
}