📄 idt.cxx
字号:
/* * Copyright (C) 1998, 1999, Jonathan S. Shapiro. * * This file is part of the EROS Operating System. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <kerninc/kernel.hxx>#include <kerninc/IRQ.hxx>#include <kerninc/Thread.hxx>#include <kerninc/util.h>#include <kerninc/Debug.hxx>#include <kerninc/SysTimer.hxx>#include <kerninc/Task.hxx>#include <kerninc/Process.hxx>#include <eros/i486/io.h>#include "lostart.hxx"#include "IDT.hxx"#include "GDT.hxx"/* #define TIMING_DEBUG *//* #define INTRDEBUG */extern "C" { extern uint32_t InterruptStackTop; extern uint32_t InterruptStackBottom; extern uint32_t InterruptStackLimit; extern int _start; extern int etext;}/* EROS IDT has null, code, data/stack, TSS */#define IDT_SIZE (IDT_ENTRIES * 8)#define IDT_CODE_ENTRY 0x8#define IDT_DATA_ENTRY 0x10#define IDT_STACK_ENTRY 0x10/* The gate interrupt number should not be zero, because * distinguishing it from divide-by-zero is too hard. There are just * too many things that show up with an exception code of zero. It * probably should be greater than 0x2f, so as to guarantee that it * will not collide with any hardware-generated interrupts. While it * is possible to detect that an interrupt <= 0x2f was generated by an * INT instruction, it is hard enough that we want to avoid it on the * key invocation path. * */class IDT IDT;extern "C" { extern void istub0x00(void); extern void istub0x01(void); extern void istub0x02(void); extern void istub0x03(void); extern void istub0x04(void); extern void istub0x05(void); extern void istub0x06(void); extern void istub0x07(void); extern void istub0x08(void); extern void istub0x09(void); extern void istub0x0a(void); extern void istub0x0b(void); extern void istub0x0c(void); extern void istub0x0d(void); extern void istub0x0e(void); extern void istub0x0f(void); extern void istub0x10(void); extern void istub0x11(void); extern void istub0x12(void); extern void istub0x13(void); extern void istub0x14(void); extern void istub0x15(void); extern void istub0x16(void); extern void istub0x17(void); extern void istub0x18(void); extern void istub0x19(void); extern void istub0x1a(void); extern void istub0x1b(void); extern void istub0x1c(void); extern void istub0x1d(void); extern void istub0x1e(void); extern void istub0x1f(void); extern void intr_clock(void); extern void istub0x21(void); extern void istub0x22(void); extern void istub0x23(void); extern void istub0x24(void); extern void istub0x25(void); extern void istub0x26(void); extern void istub0x27(void); extern void istub0x28(void); extern void istub0x29(void); extern void istub0x2a(void); extern void istub0x2b(void); extern void istub0x2c(void); extern void istub0x2d(void); extern void istub0x2e(void); extern void istub0x2f(void); extern void istub0x30(void); /* first purely software interrupt */ extern void intr_InvokeKey(void); /* key invocation interrupt */ extern void intr_CapInstr(void); /* kernel-emulated instructions */}/* Stashing the bindings in a table is slightly more space efficient * than initializing them explicitly: */struct { void (*stub)(void); bool allowUser;} IntStub[IDT_ENTRIES] = { { istub0x00, false }, { istub0x01, false }, { istub0x02, false }, { istub0x03, true }, { istub0x04, true }, { istub0x05, true }, { istub0x06, false }, { istub0x07, false }, { istub0x08, false }, { istub0x09, false }, { istub0x0a, false }, { istub0x0b, false }, { istub0x0c, false }, { istub0x0d, false }, { istub0x0e, false }, { istub0x0f, false }, { istub0x10, false }, { istub0x11, false }, { istub0x12, false }, { istub0x13, false }, { istub0x14, false }, { istub0x15, false }, { istub0x16, false }, { istub0x17, false }, { istub0x18, false }, { istub0x19, false }, { istub0x1a, false }, { istub0x1b, false }, { istub0x1c, false }, { istub0x1d, false }, { istub0x1e, false }, { istub0x1f, false }, { intr_clock, false }, { istub0x21, false }, { istub0x22, false }, { istub0x23, false }, { istub0x24, false }, { istub0x25, false }, { istub0x26, false }, { istub0x27, false }, { istub0x28, false }, { istub0x29, false }, { istub0x2a, false }, { istub0x2b, false }, { istub0x2c, false }, { istub0x2d, false }, { istub0x2e, false }, { istub0x2f, false }, { istub0x30, false }, /* voluntary yield */ { intr_InvokeKey, true }, /* key invocation interrupt */ { intr_CapInstr, true } /* kernel-emulated instructions */};GateDescriptor IdtTable[IDT_ENTRIES];/* *** INLINE FUNCTIONS FIRST */voidIDT::SetEntry(int entry, void (*procPtr)(void), bool allowUser){ uint32_t wProcPtr = (uint32_t) procPtr; IdtTable[entry].loOffset = (uint16_t) wProcPtr; IdtTable[entry].selector = Selector::KernelCode; IdtTable[entry].zero = 0; IdtTable[entry].type = 0xeu; IdtTable[entry].system = 0; /* Use RPL==1 for non-user so kernel threads can call them. */ IdtTable[entry].dpl = allowUser ? 3 : 1; IdtTable[entry].present = 1; IdtTable[entry].hiOffset = (uint16_t) (wProcPtr >> 16);}/* Moving this to IPC-vars has no appreciable impact. */IDT::VecFn IDT::IntVecEntry[IDT_ENTRIES];uint32_t IDT::IDTdescriptor[2];/* Note that the IDT gets set up immediately following the GDT, modulo * possibly being rounded up to an 8 byte boundary. This causes them * both to live on the same page, which allows us to move them around * to get out of the way of the running domain as necessary. */voidIDT::Init(){ uint32_t widt; uint32_t vec; /* Wire up IDT entries and set up to handle unbound vectors: */ for (vec = 0; vec < IDT_ENTRIES; vec++) { IdtTable[vec].present = 0; WireVector(vec, UnboundVector); SetEntry(vec, IntStub[vec].stub, IntStub[vec].allowUser); } /* Now set up to handle interrupts: */ for (vec = IntVec::IRQ0; vec <= IntVec::IRQ15; vec++) WireVector(vec, IRQ::UnboundInterrupt); /* Hand-wire a couple of common cases: */ WireVector(IntVec::Yield, YieldVector); extern void BadOpcode(fixregs_t *sa); extern void DivZeroFault(fixregs_t *sa); extern void GPFault(fixregs_t *sa); extern void SSFault(fixregs_t *sa); extern void SegNotPresFault(fixregs_t *sa); extern void BptTrap(fixregs_t *sa); extern void PageFault(fixregs_t *sa); extern void DebugException(fixregs_t *sa); extern void ReservedException(fixregs_t *sa); extern void DeviceNotAvailException(fixregs_t *sa); extern void PseudoInstrException(fixregs_t *sa); /* Hand-wire the processor-generated exceptions: */ WireVector(IntVec::BadOpcode, BadOpcode); WireVector(IntVec::DivZero, DivZeroFault); WireVector(IntVec::GeneralProtection, GPFault); WireVector(IntVec::StackSeg, SSFault); WireVector(IntVec::SegNotPresent, SegNotPresFault); WireVector(IntVec::BreakPoint, BptTrap); WireVector(IntVec::PageFault, PageFault); WireVector(IntVec::Debug, DebugException); WireVector(IntVec::DeviceNotAvail, DeviceNotAvailException); WireVector(IntVec::EmulPseudoInstr, PseudoInstrException); WireVector((IntVec::Type) 0xf, ReservedException); for (int i = 0x11; i <= 0x1f; i++) WireVector((IntVec::Type) i, ReservedException);#if 0 /* This path no longer comes through here... */ WireVector(IntVec::InvokeKey, Invoke);#endif SetupInterruptControllers(); widt = KVTOL(IdtTable); IDTdescriptor[0] = IDT_SIZE | ((widt & 0xffff) << 16); IDTdescriptor[1] = widt >> 16; lidt();}voidIDT::SetupInterruptControllers(){ /* Set up the interrupt controller chip: */ old_outb(0x20, 0x11); /* ctrlr1 init - edge triggered */ old_outb(0x21, 0x20); /* interrupts from 0x20 to 0x27 */ old_outb(0x21, 0x4); /* cascade on IRQ2 */ old_outb(0x21, 0x1); /* 8086 mode */ old_outb(0x21, 0xff); /* disable interrupts on pic1 */ old_outb(0xa0, 0x11); /* ctrlr2 init - edge triggered */ old_outb(0xa1, 0x28); /* interrupts from 0x28 to 0x2f */ old_outb(0xa1, 0x2); /* cascade on IRQ2 */ old_outb(0xa1, 0x1); /* 8086 mode */ old_outb(0xa1, 0xff); /* disable interrupts on pic1 */ old_outb(0x20,0x20); /* reset pic1 */ old_outb(0xa0,0x20); /* reset pic2 */}#if 0extern void CheckConsistency(const char *);extern bool CheckUserContexts(const char *);#endifvoidIDT::UnboundVector(fixregs_t *saveArea){#if 0 fatal( "** Unbound vector 0x%x EIP = 0x%x FVA=0x%08x Code=0x%x\n" " Trap Depth = %d pic1 = 0x%02x pic2 = 0x%02x\n", saveArea->ExceptionNo, saveArea->EIP, saveArea->ExceptionAddr, saveArea->Error, TrapDepth, pic1_cache, pic2_cache);#else fatal( "** Unbound vector 0x%x EIP = 0x%x FVA=0x%08x Code=0x%x\n", saveArea->ExceptNo, saveArea->EIP, saveArea->ExceptAddr, saveArea->Error);#endif}voidIDT::YieldVector(fixregs_t * /* sa */){ /* Simply set the global that indicates we must reschedule. This * could be inlined, but since it only happens in kernel-mode * interrupts (and then infrequently) it's better not to stick more * tests on the common interrupt path. */ Thread::ForceResched();}/* register an interrupt handler */voidIDT::WireVector(uint32_t vector, void (*pf)(fixregs_t* sa)){ IRQ::DISABLE(); IntVecEntry[vector] = pf; IRQ::ENABLE();}voidIRQ::SetHandler(uint32_t irq, void (*pf)(fixregs_t *sa)){ printf("Setting irq %d\n", irq); IDT::WireVector(IntVec::IRQ0 + irq, pf);}InterruptHandlerIRQ::GetHandler(uint32_t irq){ return IDT::GetVector(IntVec::IRQ0 + irq);}voidIRQ::UnsetHandler(uint32_t irq){ assert (irq >= 0 && irq <= 15); printf("Unsetting irq %d\n", irq); IDT::WireVector(IntVec::IRQ0 + irq, IRQ::UnboundInterrupt);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -