- redesign of the apic code
- add ioapic support - currently, all irq will forwarded to the boot processor git-svn-id: http://svn.lfbs.rwth-aachen.de/svn/scc/trunk/MetalSVM@293 315a16e6-25f9-4109-90ae-ca3045a26c18
This commit is contained in:
parent
3e1c151b5f
commit
f28fd84c68
6 changed files with 386 additions and 55 deletions
|
@ -40,7 +40,7 @@ typedef struct {
|
|||
typedef struct {
|
||||
uint32_t signature;
|
||||
uint16_t length;
|
||||
uint8_t revision;
|
||||
uint8_t revision;
|
||||
uint8_t checksum;
|
||||
uint8_t oem_id[8];
|
||||
uint8_t product_id[12];
|
||||
|
@ -49,15 +49,15 @@ typedef struct {
|
|||
uint16_t entry_count;
|
||||
uint32_t lapic;
|
||||
uint16_t extended_table_length;
|
||||
uint8_t extended_table_checksum;
|
||||
uint8_t extended_table_checksum;
|
||||
} __attribute__ ((packed)) apic_config_table_t;
|
||||
|
||||
/* APIC Processor Entry */
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
uint8_t type;
|
||||
uint8_t id;
|
||||
uint8_t version;
|
||||
uint8_t cpu;
|
||||
uint8_t cpu_flags;
|
||||
uint32_t cpu_signature;
|
||||
uint32_t cpu_feature;
|
||||
} __attribute__ ((packed)) apic_processor_entry_t;
|
||||
|
@ -71,13 +71,67 @@ typedef struct {
|
|||
uint32_t addr;
|
||||
} __attribute__ ((packed)) apic_io_entry_t;
|
||||
|
||||
/* Bus Entry */
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
uint8_t bus_id;
|
||||
char name[6];
|
||||
} __attribute__ ((packed)) apic_bus_entry_t;
|
||||
|
||||
/* I/O Interrupt Assignment Entry */
|
||||
typedef struct {
|
||||
uint8_t type; // type = 3
|
||||
uint8_t itype; // interrupt type
|
||||
uint16_t flags; // flags , PO and EL
|
||||
uint8_t src_bus; // source bus id
|
||||
uint8_t src_irq; // source interrupt (from the old bus)
|
||||
uint8_t dest_apic; // who it gets sent to 0xFF == all
|
||||
uint8_t dest_intin; // which pin it gets sent to on the IO APIC
|
||||
} __attribute__ ((packed)) apic_ioirq_entry_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint32_t vector : 8,
|
||||
delivery_mode : 3, /* 000: FIXED
|
||||
* 001: lowest prio
|
||||
* 111: ExtINT
|
||||
*/
|
||||
dest_mode : 1, /* 0: physical, 1: logical */
|
||||
delivery_status : 1,
|
||||
polarity : 1,
|
||||
irr : 1,
|
||||
trigger : 1, /* 0: edge, 1: level */
|
||||
mask : 1, /* 0: enabled, 1: disabled */
|
||||
__reserved_2 : 15;
|
||||
} bitfield;
|
||||
uint32_t whole;
|
||||
} lower;
|
||||
union {
|
||||
struct {
|
||||
uint32_t __reserved_1 : 24,
|
||||
physical_dest : 4,
|
||||
__reserved_2 : 4;
|
||||
} physical;
|
||||
|
||||
struct {
|
||||
uint32_t __reserved_1 : 24,
|
||||
logical_dest : 8;
|
||||
} logical;
|
||||
uint32_t upper;
|
||||
} dest;
|
||||
} __attribute__ ((packed)) ioapic_route_t;
|
||||
|
||||
int apic_init(void);
|
||||
void apic_eoi(void);
|
||||
uint32_t apic_cpu_id(void);
|
||||
int apic_calibration(void);
|
||||
int has_apic(void);
|
||||
int apic_is_enabled(void);
|
||||
int ioapic_inton(uint8_t irq, uint8_t apicid);
|
||||
int ioapic_intoff(uint8_t irq, uint8_t apicid);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#define MP_FLT_SIGNATURE 0x5f504d5f
|
||||
|
||||
#define APIC_ID 0x0020 // Local APIC ID Register
|
||||
#define APIC_VERSION 0x0030 // Local APIC Version Register
|
||||
#define APIC_TPR 0x0080 // Task Priority Regster
|
||||
#define APIC_EOI 0x00B0 // EOI Register
|
||||
|
@ -43,14 +44,58 @@
|
|||
#define APIC_CCR 0x0390 // Current Count Register
|
||||
#define APIC_DCR 0x03E0 // Divide Configuration Register
|
||||
|
||||
#define IOAPIC_REG_ID 0x0000 // Register index: ID
|
||||
#define IOAPIC_REG_VER 0x0001 // Register index: version
|
||||
#define IOAPIC_REG_TABLE 0x0010 // Redirection table base
|
||||
|
||||
// IO APIC MMIO structure: write reg, then read or write data.
|
||||
typedef struct {
|
||||
uint32_t reg;
|
||||
uint32_t pad[3];
|
||||
uint32_t data;
|
||||
} ioapic_t;
|
||||
|
||||
static const apic_processor_entry_t* apic_processors[MAX_CORES] = {[0 ... MAX_CORES-1] = NULL};
|
||||
static uint32_t boot_processor = MAX_CORES;
|
||||
static apic_mp_t* apic_mp = NULL;
|
||||
static apic_config_table_t* apic_config = NULL;
|
||||
static uint32_t lapic = 0;
|
||||
static volatile ioapic_t* ioapic = NULL;
|
||||
static uint32_t ncores = 1;
|
||||
static uint8_t irq_redirect[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF};
|
||||
static uint8_t initialized = 0;
|
||||
|
||||
static inline void apic_write(uint32_t addr, uint32_t value)
|
||||
static inline uint32_t lapic_read(uint32_t addr)
|
||||
{
|
||||
asm volatile ("movl (%%eax), %%edx; movl %%ebx, (%%eax)" :: "a"(addr), "b"(value) : "%edx");
|
||||
return *((uint32_t*) (lapic+addr));
|
||||
}
|
||||
|
||||
static inline void lapic_write(uint32_t addr, uint32_t value)
|
||||
{
|
||||
/*
|
||||
* to avoid ap entium bug, we have to read a apic register before
|
||||
* before we write value to this register
|
||||
*/
|
||||
asm volatile ("movl (%%eax), %%edx; movl %%ebx, (%%eax)" :: "a"(addr+lapic), "b"(value) : "%edx");
|
||||
//*((uint32_t*) (lapic+addr)) = value;
|
||||
}
|
||||
|
||||
static inline uint32_t ioapic_read(uint32_t reg)
|
||||
{
|
||||
ioapic->reg = reg;
|
||||
|
||||
return ioapic->data;
|
||||
}
|
||||
|
||||
static inline void ioapic_write(uint32_t reg, uint32_t value)
|
||||
{
|
||||
ioapic->reg = reg;
|
||||
ioapic->data = value;
|
||||
}
|
||||
|
||||
uint32_t apic_cpu_id(void)
|
||||
{
|
||||
return ((lapic_read(APIC_ID)) >> 24);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_MULTIBOOT
|
||||
|
@ -73,8 +118,8 @@ static unsigned int* search_apic(unsigned int base, unsigned int limit) {
|
|||
*/
|
||||
void apic_eoi(void)
|
||||
{
|
||||
if (lapic)
|
||||
apic_write(lapic+APIC_EOI, 0);
|
||||
if (BUILTIN_EXPECT(lapic, 1))
|
||||
lapic_write(APIC_EOI, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -83,6 +128,8 @@ void apic_eoi(void)
|
|||
*/
|
||||
int apic_calibration(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
#ifndef CONFIG_ROCKCREEK
|
||||
uint64_t ticks, old;
|
||||
uint32_t diff;
|
||||
|
@ -96,9 +143,9 @@ int apic_calibration(void)
|
|||
while((ticks = get_clock_tick()) - old == 0)
|
||||
;
|
||||
|
||||
apic_write(lapic+APIC_DCR, 0xB); // set it to 1 clock increments
|
||||
apic_write(lapic+APIC_LVT_T, 0x20030); // connects the timer to 48 and enables it
|
||||
apic_write(lapic+APIC_ICR, 0xFFFFFFFF);
|
||||
lapic_write(APIC_DCR, 0xB); // set it to 1 clock increments
|
||||
lapic_write(APIC_LVT_T, 0x2007B); // connects the timer to 123 and enables it
|
||||
lapic_write(APIC_ICR, 0xFFFFFFFF);
|
||||
|
||||
/* wait 3 time slices to determine a ICR */
|
||||
while(get_clock_tick() - ticks < 3)
|
||||
|
@ -106,9 +153,9 @@ int apic_calibration(void)
|
|||
|
||||
diff = 0xFFFFFFFF - *((uint32_t*) (lapic+APIC_CCR));
|
||||
|
||||
apic_write(lapic+APIC_DCR, 0xB); // set it to 1 clock increments
|
||||
apic_write(lapic+APIC_LVT_T, 0x20030); // connects the timer to 48 and enables it
|
||||
apic_write(lapic+APIC_ICR, diff / 3);
|
||||
lapic_write(APIC_DCR, 0xB); // set it to 1 clock increments
|
||||
lapic_write(APIC_LVT_T, 0x2007B); // connects the timer to 123 and enables it
|
||||
lapic_write(APIC_ICR, diff / 3);
|
||||
|
||||
// Now, MetalSVM is able to use the APIC => Therefore, we disable the PIC
|
||||
outportb(0xA1, 0xFF);
|
||||
|
@ -125,9 +172,9 @@ int apic_calibration(void)
|
|||
if (!has_apic())
|
||||
return -ENXIO;
|
||||
|
||||
apic_write(lapic+APIC_DCR, 0xB); // set it to 1 clock increments
|
||||
apic_write(lapic+APIC_LVT_T, 0x20030); // connects the timer to 48 and enables it
|
||||
apic_write(lapic+APIC_ICR, 0xFFFFFFFF);
|
||||
lapic_write(APIC_DCR, 0xB); // set it to 1 clock increments
|
||||
lapic_write(APIC_LVT_T, 0x2007B); // connects the timer to 123 and enables it
|
||||
lapic_write(APIC_ICR, 0xFFFFFFFF);
|
||||
|
||||
/* wait 3 time slices to determine a ICR */
|
||||
start = rdtsc();
|
||||
|
@ -139,13 +186,24 @@ int apic_calibration(void)
|
|||
|
||||
diff = 0xFFFFFFFF - *((uint32_t*) (lapic+APIC_CCR));
|
||||
|
||||
apic_write(lapic+APIC_DCR, 0xB); // set it to 1 clock increments
|
||||
apic_write(lapic+APIC_LVT_T, 0x20030); // connects the timer to 48 and enables it
|
||||
apic_write(lapic+APIC_ICR, diff / 3);
|
||||
lapic_write(APIC_DCR, 0xB); // set it to 1 clock increments
|
||||
lapic_write(APIC_LVT_T, 0x2007B); // connects the timer to 123 and enables it
|
||||
lapic_write(APIC_ICR, diff / 3);
|
||||
#endif
|
||||
|
||||
kprintf("APIC calibration detects an ICR of 0x%x\n", diff / 3);
|
||||
|
||||
irq_disable();
|
||||
if (ioapic) {
|
||||
// now, we don't longer need the IOAPIC timer and turn it off
|
||||
ioapic_intoff(0, apic_processors[boot_processor]->id);
|
||||
// now lets turn everything else on
|
||||
for(i=1; i<24; i++)
|
||||
ioapic_inton(i, apic_processors[boot_processor]->id);
|
||||
}
|
||||
initialized = 1;
|
||||
irq_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -153,6 +211,7 @@ static int apic_probe(void)
|
|||
{
|
||||
size_t addr;
|
||||
uint32_t i, count;
|
||||
int isa_bus = -1;
|
||||
|
||||
// searching MP signature in the reserved memory areas
|
||||
#ifdef CONFIG_MULTIBOOT
|
||||
|
@ -200,15 +259,59 @@ found_mp:
|
|||
goto no_mp;
|
||||
}
|
||||
|
||||
addr = (size_t) apic_config;
|
||||
addr += sizeof(apic_config_table_t);
|
||||
if (addr % 4)
|
||||
addr += 4 - addr % 4;
|
||||
|
||||
// search the ISA bus => required to redirect the IRQs
|
||||
for(i=0; i<apic_config->entry_count; i++) {
|
||||
switch(*((uint8_t*) addr)) {
|
||||
case 0:
|
||||
addr += 20;
|
||||
break;
|
||||
case 1: {
|
||||
apic_bus_entry_t* mp_bus;
|
||||
|
||||
mp_bus = (apic_bus_entry_t*) addr;
|
||||
if (mp_bus->name[0] == 'I' && mp_bus->name[1] == 'S' &&
|
||||
mp_bus->name[2] == 'A')
|
||||
isa_bus = i;
|
||||
}
|
||||
default:
|
||||
addr += 8;
|
||||
}
|
||||
}
|
||||
|
||||
addr = (size_t) apic_config;
|
||||
addr += sizeof(apic_config_table_t);
|
||||
if (addr % 4)
|
||||
addr += 4 - addr % 4;
|
||||
|
||||
for(i=0, count=0; i<apic_config->entry_count; i++) {
|
||||
if (*((uint8_t*) addr) == 0) {
|
||||
if (*((uint8_t*) addr) == 0) { // cpu entry
|
||||
if (i < MAX_CORES) {
|
||||
apic_processors[i] = (apic_processor_entry_t*) addr;
|
||||
if (!(apic_processors[i]->cpu_flags & 0x01)) // is the processor usable?
|
||||
apic_processors[i] = NULL;
|
||||
else if (apic_processors[i]->cpu_flags & 0x02)
|
||||
boot_processor = i;
|
||||
}
|
||||
count++;
|
||||
addr += 20;
|
||||
} else if (*((uint8_t*) addr) == 2) { // IO_APIC
|
||||
apic_io_entry_t* io_entry = (apic_io_entry_t*) addr;
|
||||
ioapic = (ioapic_t*) io_entry->addr;
|
||||
addr += 8;
|
||||
kprintf("Found IOAPIC at 0x%x (ver. 0x%x)\n", ioapic,
|
||||
ioapic_read(IOAPIC_REG_VER));
|
||||
} else if (*((uint8_t*) addr) == 3) { // IO_INT
|
||||
apic_ioirq_entry_t* extint = (apic_ioirq_entry_t*) addr;
|
||||
if (extint->src_bus == isa_bus) {
|
||||
irq_redirect[extint->src_irq] = extint->dest_intin;
|
||||
kprintf("Redirect irq %u -> %u\n", extint->src_irq, extint->dest_intin);
|
||||
}
|
||||
addr += 8;
|
||||
} else addr += 8;
|
||||
}
|
||||
kprintf("Found %u cores\n", count);
|
||||
|
@ -223,13 +326,11 @@ check_lapic:
|
|||
if (apic_config) {
|
||||
lapic = apic_config->lapic;
|
||||
} else {
|
||||
uint32_t eax, edx, dummy;
|
||||
uint32_t edx, dummy;
|
||||
|
||||
cpuid(0x1, &eax, &dummy, &dummy, &edx);
|
||||
cpuid(0x1, &dummy, &dummy, &dummy, &edx);
|
||||
if (edx & (1 << 9))
|
||||
lapic = 0xFEE00000;
|
||||
|
||||
kprintf("Processor familiy %u, model %u, stepping %u\n", (eax>>8)&0xF, (eax>>4)&0xF, eax&0xF);
|
||||
}
|
||||
|
||||
if (!lapic)
|
||||
|
@ -259,18 +360,27 @@ no_mp:
|
|||
int apic_init(void)
|
||||
{
|
||||
int ret;
|
||||
uint8_t i;
|
||||
|
||||
ret = apic_probe();
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
apic_write(lapic+APIC_TPR, 0x00); // allow all interrupts
|
||||
apic_write(lapic+APIC_LVT_T, 0x10000); // disable timer interrupt
|
||||
apic_write(lapic+APIC_LVT_PMC, 0x10000);// disable performance counter interrupt
|
||||
apic_write(lapic+APIC_LINT0, 0x31); // connect LINT0 to idt entry 49
|
||||
apic_write(lapic+APIC_LINT1, 0x32); // connect LINT1 to idt entry 50
|
||||
apic_write(lapic+APIC_LVT_ER, 0x33); // connect error to idt entry 51
|
||||
apic_write(lapic+APIC_SVR, 0x17F); // enable the apic and connect to the idt entry 207
|
||||
lapic_write(APIC_TPR, 0x00); // allow all interrupts
|
||||
lapic_write(APIC_LVT_T, 0x10000); // disable timer interrupt
|
||||
lapic_write(APIC_LVT_PMC, 0x10000);// disable performance counter interrupt
|
||||
lapic_write(APIC_LINT0, 0x7C); // connect LINT0 to idt entry 124
|
||||
lapic_write(APIC_LINT1, 0x7D); // connect LINT1 to idt entry 125
|
||||
lapic_write(APIC_LVT_ER, 0x7E); // connect error to idt entry 126
|
||||
lapic_write(APIC_SVR, 0x17F); // enable the apic and connect to the idt entry 127
|
||||
|
||||
if (ioapic) {
|
||||
// enable timer interrupt
|
||||
ioapic_inton(0, apic_processors[boot_processor]->id);
|
||||
// now lets turn everything else off
|
||||
for(i=1; i<24; i++)
|
||||
ioapic_intoff(i, apic_processors[boot_processor]->id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -279,3 +389,71 @@ int has_apic(void)
|
|||
{
|
||||
return (lapic != 0);
|
||||
}
|
||||
|
||||
int apic_is_enabled(void)
|
||||
{
|
||||
return ((lapic != 0) && initialized);
|
||||
}
|
||||
|
||||
int ioapic_inton(uint8_t irq, uint8_t apicid)
|
||||
{
|
||||
ioapic_route_t route;
|
||||
uint32_t off;
|
||||
|
||||
if (BUILTIN_EXPECT(irq > 24, 0)){
|
||||
kprintf("IOAPIC: trying to turn on irq %i which is too high\n", irq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (irq < 16)
|
||||
off = irq_redirect[irq]*2;
|
||||
else
|
||||
off = irq*2;
|
||||
|
||||
route.lower.bitfield.dest_mode = 0;
|
||||
route.lower.bitfield.mask = 0;
|
||||
route.dest.physical.physical_dest = apicid; // send to the boot processor
|
||||
route.lower.bitfield.delivery_mode = 0;
|
||||
route.lower.bitfield.polarity = 0;
|
||||
route.lower.bitfield.trigger = 0;
|
||||
route.lower.bitfield.vector = 0x20+irq;
|
||||
route.lower.bitfield.mask = 0; // turn it on (stop masking)
|
||||
|
||||
ioapic_write(IOAPIC_REG_TABLE+off, route.lower.whole);
|
||||
ioapic_write(IOAPIC_REG_TABLE+1+off, route.dest.upper);
|
||||
|
||||
route.dest.upper = ioapic_read(IOAPIC_REG_TABLE+1+off);
|
||||
route.lower.whole = ioapic_read(IOAPIC_REG_TABLE+off);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ioapic_intoff(uint8_t irq, uint8_t apicid)
|
||||
{
|
||||
ioapic_route_t route;
|
||||
uint32_t off;
|
||||
|
||||
if (BUILTIN_EXPECT(irq > 24, 0)){
|
||||
kprintf("IOAPIC: trying to turn on irq %i which is too high\n", irq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (irq < 16)
|
||||
off = irq_redirect[irq]*2;
|
||||
else
|
||||
off = irq*2;
|
||||
|
||||
route.lower.bitfield.dest_mode = 0;
|
||||
route.lower.bitfield.mask = 0;
|
||||
route.dest.physical.physical_dest = apicid;
|
||||
route.lower.bitfield.delivery_mode = 0;
|
||||
route.lower.bitfield.polarity = 0;
|
||||
route.lower.bitfield.trigger = 0;
|
||||
route.lower.bitfield.vector = 0x20+irq;
|
||||
route.lower.bitfield.mask = 1; // turn it off (start masking)
|
||||
|
||||
ioapic_write(IOAPIC_REG_TABLE+off, route.lower.whole);
|
||||
ioapic_write(IOAPIC_REG_TABLE+1+off, route.dest.upper);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -473,6 +473,14 @@ global irq12
|
|||
global irq13
|
||||
global irq14
|
||||
global irq15
|
||||
global irq16
|
||||
global irq17
|
||||
global irq18
|
||||
global irq19
|
||||
global irq20
|
||||
global irq21
|
||||
global irq22
|
||||
global irq23
|
||||
global apic_timer
|
||||
global apic_lint0
|
||||
global apic_lint1
|
||||
|
@ -518,9 +526,9 @@ irq0:
|
|||
; cli
|
||||
push byte 0
|
||||
push byte 32
|
||||
pusha
|
||||
|
||||
Lirq0:
|
||||
pusha
|
||||
push esp
|
||||
call irq_handler
|
||||
add esp, 4
|
||||
|
@ -681,13 +689,84 @@ irq15:
|
|||
push byte 47
|
||||
jmp irq_common_stub
|
||||
|
||||
; 48: IRQ16
|
||||
irq16:
|
||||
; irq16 - irq23 are registered as "Interrupt Gate"
|
||||
; Therefore, the interrupt flag (IF) is already cleared.
|
||||
; cli
|
||||
push byte 0
|
||||
push byte 48
|
||||
jmp irq_common_stub
|
||||
|
||||
; 49: IRQ17
|
||||
irq17:
|
||||
; irq16- irq23 are registered as "Interrupt Gate"
|
||||
; Therefore, the interrupt flag (IF) is already cleared.
|
||||
; cli
|
||||
push byte 0
|
||||
push byte 49
|
||||
jmp irq_common_stub
|
||||
|
||||
; 50: IRQ18
|
||||
irq18:
|
||||
; irq16 - irq23 are registered as "Interrupt Gate"
|
||||
; Therefore, the interrupt flag (IF) is already cleared.
|
||||
; cli
|
||||
push byte 0
|
||||
push byte 50
|
||||
jmp irq_common_stub
|
||||
|
||||
; 51: IRQ19
|
||||
irq19:
|
||||
; irq16 - irq23 are registered as "Interrupt Gate"
|
||||
; Therefore, the interrupt flag (IF) is already cleared.
|
||||
; cli
|
||||
push byte 0
|
||||
push byte 51
|
||||
jmp irq_common_stub
|
||||
|
||||
; 52: IRQ20
|
||||
irq20:
|
||||
; irq16- irq23 are registered as "Interrupt Gate"
|
||||
; Therefore, the interrupt flag (IF) is already cleared.
|
||||
; cli
|
||||
push byte 0
|
||||
push byte 52
|
||||
jmp irq_common_stub
|
||||
|
||||
; 53: IRQ21
|
||||
irq21:
|
||||
; irq16 - irq23 are registered as "Interrupt Gate"
|
||||
; Therefore, the interrupt flag (IF) is already cleared.
|
||||
; cli
|
||||
push byte 0
|
||||
push byte 53
|
||||
jmp irq_common_stub
|
||||
|
||||
; 54: IRQ22
|
||||
irq22:
|
||||
; irq16- irq23 are registered as "Interrupt Gate"
|
||||
; Therefore, the interrupt flag (IF) is already cleared.
|
||||
; cli
|
||||
push byte 0
|
||||
push byte 54
|
||||
jmp irq_common_stub
|
||||
|
||||
; 55: IRQ23
|
||||
irq23:
|
||||
; irq16 - irq23 are registered as "Interrupt Gate"
|
||||
; Therefore, the interrupt flag (IF) is already cleared.
|
||||
; cli
|
||||
push byte 0
|
||||
push byte 55
|
||||
jmp irq_common_stub
|
||||
|
||||
apic_timer:
|
||||
; apic timer is registered as "Interrupt Gate"
|
||||
; Therefore, the interrupt flag (IF) is already cleared.
|
||||
; cli
|
||||
push byte 0
|
||||
push byte 48
|
||||
pusha
|
||||
push byte 123
|
||||
; we reuse code of the "traditional" timer interrupt (PIC)
|
||||
jmp Lirq0
|
||||
|
||||
|
@ -696,7 +775,7 @@ apic_lint0:
|
|||
; Therefore, the interrupt flag (IF) is already cleared.
|
||||
; cli
|
||||
push byte 0
|
||||
push byte 49
|
||||
push byte 124
|
||||
jmp irq_common_stub
|
||||
|
||||
apic_lint1:
|
||||
|
@ -704,7 +783,7 @@ apic_lint1:
|
|||
; Therefore, the interrupt flag (IF) is already cleared.
|
||||
; cli
|
||||
push byte 0
|
||||
push byte 50
|
||||
push byte 125
|
||||
jmp irq_common_stub
|
||||
|
||||
apic_error:
|
||||
|
@ -712,7 +791,7 @@ apic_error:
|
|||
; Therefore, the interrupt flag (IF) is already cleared.
|
||||
; cli
|
||||
push byte 0
|
||||
push byte 51
|
||||
push byte 126
|
||||
jmp irq_common_stub
|
||||
|
||||
apic_svr:
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
* This file is part of MetalSVM.
|
||||
*/
|
||||
|
||||
#include <metalsvm/stdio.h>
|
||||
#include <metalsvm/string.h>
|
||||
#include <metalsvm/tasks.h>
|
||||
#include <metalsvm/errno.h>
|
||||
|
@ -45,6 +46,14 @@ extern void irq12(void);
|
|||
extern void irq13(void);
|
||||
extern void irq14(void);
|
||||
extern void irq15(void);
|
||||
extern void irq16(void);
|
||||
extern void irq17(void);
|
||||
extern void irq18(void);
|
||||
extern void irq19(void);
|
||||
extern void irq20(void);
|
||||
extern void irq21(void);
|
||||
extern void irq22(void);
|
||||
extern void irq23(void);
|
||||
extern void apic_timer(void);
|
||||
extern void apic_lint0(void);
|
||||
extern void apic_lint1(void);
|
||||
|
@ -57,7 +66,7 @@ extern void apic_svr(void);
|
|||
* This array is actually an array of function pointers. We use
|
||||
* this to handle custom IRQ handlers for a given IRQ
|
||||
*/
|
||||
static void *irq_routines[MAX_HANDLERS] = {[0 ... MAX_HANDLERS-1] = NULL };
|
||||
static void* irq_routines[MAX_HANDLERS] = {[0 ... MAX_HANDLERS-1] = NULL };
|
||||
|
||||
/* This installs a custom IRQ handler for the given IRQ */
|
||||
int irq_install_handler(unsigned int irq, irq_handler_t handler)
|
||||
|
@ -152,13 +161,30 @@ static int irq_install(void)
|
|||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
|
||||
if (has_apic()) {
|
||||
idt_set_gate(48, (unsigned)apic_timer, KERNEL_CODE_SELECTOR,
|
||||
idt_set_gate(48, (unsigned)irq16, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(49, (unsigned)apic_lint0, KERNEL_CODE_SELECTOR,
|
||||
idt_set_gate(49, (unsigned)irq17, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(50, (unsigned)apic_lint1, KERNEL_CODE_SELECTOR,
|
||||
idt_set_gate(50, (unsigned)irq18, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(51, (unsigned)apic_error, KERNEL_CODE_SELECTOR,
|
||||
idt_set_gate(51, (unsigned)irq19, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(52, (unsigned)irq20, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(53, (unsigned)irq21, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(54, (unsigned)irq22, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(55, (unsigned)irq23, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
|
||||
idt_set_gate(123, (unsigned)apic_timer, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(124, (unsigned)apic_lint0, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(125, (unsigned)apic_lint1, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(126, (unsigned)apic_error, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(127, (unsigned)apic_svr, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
|
@ -196,16 +222,10 @@ void irq_handler(struct state *s)
|
|||
/* This is a blank function pointer */
|
||||
void (*handler) (struct state * s);
|
||||
|
||||
if (s->int_no - 32 > MAX_HANDLERS) {
|
||||
apic_eoi();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out if we have a custom handler to run for this
|
||||
* IRQ and then finally, run it
|
||||
*/
|
||||
|
||||
*/
|
||||
handler = irq_routines[s->int_no - 32];
|
||||
if (handler)
|
||||
handler(s);
|
||||
|
@ -214,7 +234,7 @@ void irq_handler(struct state *s)
|
|||
* If the IDT entry that was invoked was greater-than-or-equal to 48,
|
||||
* then we use the APIC
|
||||
*/
|
||||
if (s->int_no >= 48) {
|
||||
if (apic_is_enabled() || s->int_no >= 123) {
|
||||
apic_eoi();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -173,7 +173,7 @@ void fault_handler(struct state *s)
|
|||
kputs(" Exception.\n");
|
||||
|
||||
/* Now, we signalize that we have handled the interrupt */
|
||||
if (has_apic())
|
||||
if (apic_is_enabled())
|
||||
apic_eoi();
|
||||
else
|
||||
outportb(0x20, 0x20);
|
||||
|
|
|
@ -81,11 +81,11 @@ int timer_init(void)
|
|||
uint64_t start;
|
||||
|
||||
/*
|
||||
* Installs 'timer_handler' for the PIC (0) and APIC timer (16),
|
||||
* Installs 'timer_handler' for the PIC and APIC timer,
|
||||
* only one handler will be later used.
|
||||
*/
|
||||
irq_install_handler(0, timer_handler);
|
||||
irq_install_handler(16, timer_handler);
|
||||
irq_install_handler(123-32, timer_handler);
|
||||
|
||||
/*
|
||||
* The Rock Creek processor doesn't posseess an tradional PIC.
|
||||
|
|
Loading…
Add table
Reference in a new issue