]> Zhao Yanbai Git Server - minix.git/commitdiff
Local APIC
authorTomas Hruby <tom@minix3.org>
Mon, 16 Nov 2009 21:41:44 +0000 (21:41 +0000)
committerTomas Hruby <tom@minix3.org>
Mon, 16 Nov 2009 21:41:44 +0000 (21:41 +0000)
- local APIC timer used as the source of time

- PIC is still used as the hw interrupt controller as we don't have
  enough info without ACPI or MPS to set up IO APICs

- remapping of APIC when switching paging on, uses the new mechanism
  to tell VM what phys areas to map in kernel's virtual space

- one more step to SMP

based on code by Arun C.

24 files changed:
include/minix/cpufeature.h
include/sys/vm_i386.h
kernel/arch/i386/Makefile
kernel/arch/i386/apic.c [new file with mode: 0644]
kernel/arch/i386/apic.h [new file with mode: 0644]
kernel/arch/i386/apic_asm.S [new file with mode: 0644]
kernel/arch/i386/apic_asm.h [new file with mode: 0644]
kernel/arch/i386/clock.c
kernel/arch/i386/glo.h [new file with mode: 0644]
kernel/arch/i386/i8259.c
kernel/arch/i386/include/archconst.h
kernel/arch/i386/klib386.S
kernel/arch/i386/memory.c
kernel/arch/i386/protect.c
kernel/arch/i386/proto.h
kernel/arch/i386/sconst.h
kernel/arch/i386/system.c
kernel/debug.h
kernel/glo.h
kernel/kernel.h
kernel/main.c
kernel/proto.h
kernel/start.c
lib/i386/misc/_cpufeature.c

index 0dcb9a154d4f8160ecea7eaab65ec3487f18d583..a5fec4adada9d42a284ef4bcc92edfd77afe256a 100644 (file)
@@ -2,8 +2,10 @@
 #ifndef _MINIX_CPUFEATURE_H
 #define _MINIX_CPUFEATURE_H 1
 
-#define _CPUF_I386_PSE 1       /* Page Size Extension */
-#define _CPUF_I386_PGE 2       /* Page Global Enable */
+#define _CPUF_I386_PSE                 1       /* Page Size Extension */
+#define _CPUF_I386_PGE                 2       /* Page Global Enable */
+#define _CPUF_I386_APIC_ON_CHIP        3       /* APIC is present on the chip */
+#define _CPUF_I386_TSC         4       /* Timestamp counter present */
 
 _PROTOTYPE(int _cpufeature, (int featureno));
 
index 12ea709ccb39cd90e82ec7519a0edb686f9a660a..da94c341b9d977752e3b63f35c73c634899257de 100644 (file)
@@ -70,7 +70,9 @@ sys/vm_i386.h
 #define I386_VM_PFE_U  0x04    /* CPU in user mode (otherwise supervisor) */
 
 /* CPUID flags */
-#define CPUID1_EDX_PSE (1L <<  3)      /* Page Size Extension */
-#define CPUID1_EDX_PGE (1L << 13)      /* Page Global (bit) Enable */
+#define CPUID1_EDX_PSE                 (1L <<  3)      /* Page Size Extension */
+#define CPUID1_EDX_PGE                 (1L << 13)      /* Page Global (bit) Enable */
+#define CPUID1_EDX_APIC_ON_CHIP (1L << 9)      /* APIC is present on the chip */
+#define CPUID1_EDX_TSC         (1L << 4)       /* Timestamp counter present */
 
 #endif /* __SYS_VM_386_H__ */
index afbeea6687884ab5be6cd7b50b10fc697850e481..0779512f7dec6270b75577be82daebbd614e15c1 100644 (file)
@@ -20,7 +20,9 @@ OBJS= arch_do_vmctl.o \
        memory.o \
        mpx386.o \
        protect.o \
-       system.o
+       system.o \
+       apic.o \
+       apic_asm.o
 
 CPPFLAGS=-Iinclude
 CFLAGS=$(CPPFLAGS) -Wall $(CPROFILE)
@@ -80,6 +82,11 @@ mpx386.o: mpx386.S
        gas2ack $@.tmp $@.s
        $(CC) $(CFLAGS) -c -o $@ $@.s
 
+apic_asm.o: apic_asm.S
+       $(CC) $(CFLAGS) -E -D__ASSEMBLY__ -o $@.tmp $<
+       gas2ack $@.tmp $@.s
+       $(CC) $(CFLAGS) -c -o $@ $@.s
+
 .c.o:
        $(CC) $(CFLAGS) -c -o $@ $<
 
diff --git a/kernel/arch/i386/apic.c b/kernel/arch/i386/apic.c
new file mode 100644 (file)
index 0000000..b52a73d
--- /dev/null
@@ -0,0 +1,559 @@
+/*
+ * APIC handling routines. APIC is a requirement for SMP
+ */
+#include "../../kernel.h"
+
+#include <unistd.h>
+#include <ibm/cmos.h>
+#include <ibm/bios.h>
+#include <minix/portio.h>
+
+#include <minix/syslib.h>
+
+#include "../../proc.h"
+#include "../..//glo.h"
+#include "proto.h"
+
+#include <minix/u64.h>
+
+#include "apic.h"
+#include "apic_asm.h"
+#include "../../clock.h"
+#include "glo.h"
+
+#define APIC_ENABLE            0x100
+#define APIC_FOCUS             (~(1 << 9))
+#define APIC_SIV               0xFF
+
+#define APIC_TDCR_2    0x00
+#define APIC_TDCR_4    0x01
+#define APIC_TDCR_8    0x02
+#define APIC_TDCR_16   0x03
+#define APIC_TDCR_32   0x08
+#define APIC_TDCR_64   0x09
+#define APIC_TDCR_128  0x0a
+#define APIC_TDCR_1    0x0b
+
+#define IS_SET(mask)           (mask)
+#define IS_CLEAR(mask)         0
+
+#define APIC_LVTT_VECTOR_MASK  0x000000FF
+#define APIC_LVTT_DS_PENDING   (1 << 12)
+#define APIC_LVTT_MASK         (1 << 16)
+#define APIC_LVTT_TM           (1 << 17)
+
+#define APIC_LVT_IIPP_MASK     0x00002000
+#define APIC_LVT_IIPP_AH       0x00002000
+#define APIC_LVT_IIPP_AL       0x00000000
+
+#define APIC_LVT_TM_ONESHOT    IS_CLEAR(APIC_LVTT_TM)
+#define APIC_LVT_TM_PERIODIC   IS_SET(APIC_LVTT_TM)
+
+#define APIC_SVR_SWEN          0x00000100
+#define APIC_SVR_FOCUS         0x00000200
+
+#define IOAPIC_REGSEL          0x0
+#define IOAPIC_RW              0x10
+
+#define APIC_ICR_DM_MASK               0x00000700
+#define APIC_ICR_VECTOR                        APIC_LVTT_VECTOR_MASK
+#define APIC_ICR_DM_FIXED              (0 << 8)
+#define APIC_ICR_DM_LOWEST_PRIORITY    (1 << 8)
+#define APIC_ICR_DM_SMI                        (2 << 8)
+#define APIC_ICR_DM_RESERVED           (3 << 8)
+#define APIC_ICR_DM_NMI                        (4 << 8)
+#define APIC_ICR_DM_INIT               (5 << 8)
+#define APIC_ICR_DM_STARTUP            (6 << 8)
+#define APIC_ICR_DM_EXTINT             (7 << 8)
+
+#define APIC_ICR_DM_PHYSICAL           (0 << 11)
+#define APIC_ICR_DM_LOGICAL            (1 << 11)
+
+#define APIC_ICR_DELIVERY_PENDING      (1 << 12)
+
+#define APIC_ICR_INT_POLARITY          (1 << 13)
+#define APIC_ICR_INTPOL_LOW            IS_SET(APIC_ICR_INT_POLARITY)
+#define APIC_ICR_INTPOL_HIGH           IS_CLEAR(APIC_ICR_INT_POLARITY)
+
+#define APIC_ICR_LEVEL_ASSERT          (1 << 14)
+#define APIC_ICR_LEVEL_DEASSERT                (0 << 14)
+
+#define APIC_ICR_TRIGGER               (1 << 15)
+#define APIC_ICR_TM_LEVEL              IS_CLEAR(APIC_ICR_TRIGGER)
+#define APIC_ICR_TM_EDGE               IS_CLEAR(APIC_ICR_TRIGGER)
+
+#define APIC_ICR_INT_MASK              (1 << 16)
+
+#define APIC_ICR_DEST_FIELD            (0 << 18)
+#define APIC_ICR_DEST_SELF             (1 << 18)
+#define APIC_ICR_DEST_ALL              (2 << 18)
+#define APIC_ICR_DEST_ALL_BUT_SELF     (3 << 18)
+
+#define IA32_APIC_BASE 0x1b
+#define IA32_APIC_BASE_ENABLE_BIT      11
+
+/* currently only 2 interrupt priority levels are used */
+#define SPL0                           0x0
+#define        SPLHI                           0xF
+
+/*
+ * to make APIC work if SMP is not configured, we need to set the maximal number
+ * fo CPUS to 1, cpuid to return 0 and the current cpu is always BSP
+ */
+#define CONFIG_MAX_CPUS 1
+#define cpu_is_bsp(x) 1
+
+PRIVATE int cpuid(void)
+{
+       return 0;
+}
+
+#define lapic_write_icr1(val)  lapic_write(LAPIC_ICR1, val)
+#define lapic_write_icr2(val)  lapic_write(LAPIC_ICR2, val)
+
+#define lapic_read_icr1(x)     lapic_read(LAPIC_ICR1)
+#define lapic_read_icr2(x)     lapic_read(LAPIC_ICR2)
+
+#define VERBOSE_APIC(x) x
+
+PUBLIC int reboot_type;
+PUBLIC int ioapic_enabled;
+PUBLIC u32_t ioapic_id_mask[8], lapic_id_mask[8];
+PUBLIC u32_t lapic_addr_vaddr;
+PUBLIC u32_t lapic_addr;
+PUBLIC u32_t lapic_eoi_addr;
+PUBLIC u32_t lapic_taskpri_addr;
+PUBLIC int bsp_lapic_id;
+
+PRIVATE volatile int probe_ticks;
+PRIVATE        u64_t tsc0, tsc1;
+PRIVATE        u32_t lapic_tctr0, lapic_tctr1;
+
+u8_t apicid2cpuid[MAX_NR_APICIDS+1];
+unsigned apic_imcrp;
+unsigned nioapics;
+unsigned nbuses;
+unsigned nintrs;
+unsigned nlints;
+
+/*
+ * FIXME this should be a cpulocal variable but there are some problems with
+ * arch specific cpulocals. As this variable is write-once-read-only it is ok to
+ * have at as an array until we resolve the cpulocals properly
+ */
+PRIVATE u32_t lapic_bus_freq[CONFIG_MAX_CPUS];
+/* the probe period will be roughly 100ms */
+#define PROBE_TICKS    (system_hz / 10)
+
+PRIVATE u32_t pci_config_intr_data;
+PRIVATE u32_t ioapic_extint_assigned = 0;
+PRIVATE int lapic_extint_assigned = 0;
+
+PRIVATE int calib_clk_handler(irq_hook_t * hook)
+{
+       u32_t tcrt;
+       u64_t tsc;
+
+       probe_ticks++;
+       if (cpu_has_tsc) {
+               read_tsc_64(&tsc);
+       }
+       tcrt = lapic_read(LAPIC_TIMER_CCR);
+
+
+       if (probe_ticks == 1) {
+               lapic_tctr0 = tcrt;
+               tsc0 = tsc;
+       }
+       else if (probe_ticks == PROBE_TICKS) {
+               lapic_tctr1 = tcrt;
+               tsc1 = tsc;
+       }
+
+       return 1;
+}
+
+PUBLIC void apic_calibrate_clocks(void)
+{
+       u32_t lvtt, val, lapic_delta;
+       u64_t tsc_delta;
+       u32_t cpu_freq;
+
+       irq_hook_t calib_clk;
+
+       BOOT_VERBOSE(kprintf("Calibrating clock\n"));
+       /*
+        * Set Initial count register to the highest value so it does not
+        * underflow during the testing period
+        * */
+       val = 0xffffffff;
+       lapic_write (LAPIC_TIMER_ICR, val);
+
+       /* Set Current count register */
+       val = 0;
+       lapic_write (LAPIC_TIMER_CCR, val);
+
+       lvtt = lapic_read(LAPIC_TIMER_DCR) & ~0x0b;
+        /* Set Divide configuration register to 1 */
+       lvtt = APIC_TDCR_1;
+       lapic_write(LAPIC_TIMER_DCR, lvtt);
+
+       /*
+        * mask the APIC timer interrupt in the LVT Timer Register so that we
+        * don't get an interrupt upon underflow which we don't know how to
+        * handle right know. If underflow happens, the system will not continue
+        * as something is wrong with the clock IRQ 0 and we cannot calibrate
+        * the clock which mean that we cannot run processes
+        */
+       lvtt = lapic_read (LAPIC_LVTTR);
+       lvtt |= APIC_LVTT_MASK;
+       lapic_write (LAPIC_LVTTR, lvtt);
+
+       /* set the probe, we use the legacy timer, IRQ 0 */
+       put_irq_handler(&calib_clk, CLOCK_IRQ, calib_clk_handler);
+
+       /* set the PIC timer to get some time */
+       intr_enable();
+       init_8253A_timer(system_hz);
+
+       /* loop for some time to get a sample */
+       while(probe_ticks < PROBE_TICKS);
+
+       intr_disable();
+       stop_8253A_timer();
+
+       /* remove the probe */
+       rm_irq_handler(&calib_clk);
+
+       lapic_delta = lapic_tctr0 - lapic_tctr1;
+       tsc_delta = sub64(tsc1, tsc0);
+
+       lapic_bus_freq[cpuid()] = system_hz * lapic_delta / (PROBE_TICKS - 1);
+       BOOT_VERBOSE(kprintf("APIC bus freq %lu MHz\n",
+                               lapic_bus_freq[cpuid()] / 1000000));
+       cpu_freq = div64u(tsc_delta, PROBE_TICKS - 1) * system_hz;
+       BOOT_VERBOSE(kprintf("CPU %d freq %lu MHz\n", cpuid(),
+                               cpu_freq / 1000000));
+}
+
+PRIVATE void lapic_set_timer_one_shot(u32_t value)
+{
+       /* sleep in micro seconds */
+       u32_t lvtt;
+       u32_t ticks_per_us;
+       u8_t cpu = cpuid ();
+
+       ticks_per_us = lapic_bus_freq[cpu] / 1000000;
+
+       /* calculate divisor and count from value */
+       lvtt = APIC_TDCR_1;
+       lapic_write(LAPIC_TIMER_DCR, lvtt);
+
+       /* configure timer as one-shot */
+       lvtt = APIC_TIMER_INT_VECTOR;
+       lapic_write(LAPIC_LVTTR, lvtt);
+
+       lapic_write(LAPIC_TIMER_ICR, value * ticks_per_us);
+}
+
+PUBLIC void lapic_set_timer_periodic(unsigned freq)
+{
+       /* sleep in micro seconds */
+       u32_t lvtt;
+       u32_t lapic_ticks_per_clock_tick;
+       u8_t cpu = cpuid();
+
+       lapic_ticks_per_clock_tick = lapic_bus_freq[cpu] / freq;
+
+       lvtt = APIC_TDCR_1;
+       lapic_write(LAPIC_TIMER_DCR, lvtt);
+
+       /* configure timer as periodic */
+       lvtt = APIC_LVT_TM_PERIODIC | APIC_TIMER_INT_VECTOR;
+       lapic_write(LAPIC_LVTTR, lvtt);
+
+       lapic_write(LAPIC_TIMER_ICR, lapic_ticks_per_clock_tick);
+}
+
+PUBLIC void lapic_stop_timer(void)
+{
+       u32_t lvtt;
+       lapic_read(LAPIC_LVTTR);
+       lapic_write(LAPIC_LVTTR, lvtt | APIC_LVTT_MASK);
+}
+
+PUBLIC void lapic_microsec_sleep(unsigned count)
+{
+       lapic_set_timer_one_shot(count);
+       while (lapic_read (LAPIC_TIMER_CCR));
+}
+
+PUBLIC  u32_t lapic_errstatus (void)
+{
+       lapic_write(LAPIC_ESR, 0);
+       return lapic_read(LAPIC_ESR);
+}
+
+PUBLIC void lapic_disable(void)
+{
+       /* Disable current APIC and close interrupts from PIC */
+       u32_t val;
+
+       if (!lapic_addr)
+               return;
+       {
+               /* leave it enabled if imcr is not set */
+               val = lapic_read(LAPIC_LINT0);
+               val &= ~(APIC_ICR_DM_MASK|APIC_ICR_INT_MASK);
+               val |= APIC_ICR_DM_EXTINT; /* ExtINT at LINT0 */
+               lapic_write (LAPIC_LINT0, val);
+               return;
+       }
+
+       val = lapic_read(LAPIC_LINT0) & 0xFFFE58FF;
+       val |= APIC_ICR_INT_MASK;
+       lapic_write (LAPIC_LINT0, val);
+
+       val = lapic_read(LAPIC_LINT1) & 0xFFFE58FF;
+       val |= APIC_ICR_INT_MASK;
+       lapic_write (LAPIC_LINT1, val);
+
+       val = lapic_read(LAPIC_SIVR) & 0xFFFFFF00;
+       val &= ~APIC_ENABLE;
+       lapic_write(LAPIC_SIVR, val);
+}
+
+PRIVATE void lapic_enable_no_lints(void)
+{
+       u32_t val;
+
+       val = lapic_read(LAPIC_LINT0);
+       lapic_extint_assigned = (val & APIC_ICR_DM_MASK) == APIC_ICR_DM_EXTINT;
+       val &= ~(APIC_ICR_DM_MASK|APIC_ICR_INT_MASK);
+
+       if (!ioapic_enabled && cpu_is_bsp(cpuid()))
+               val |= (APIC_ICR_DM_EXTINT); /* ExtINT at LINT0 */
+       else
+               val |= (APIC_ICR_DM_EXTINT|APIC_ICR_INT_MASK); /* Masked ExtINT at LINT0 */
+
+       lapic_write (LAPIC_LINT0, val);
+
+       val = lapic_read(LAPIC_LINT1);
+       val &= ~(APIC_ICR_DM_MASK|APIC_ICR_INT_MASK);
+
+       if (!ioapic_enabled && cpu_is_bsp(cpuid()))
+               val |= APIC_ICR_DM_NMI;
+       else
+               val |= (APIC_ICR_DM_NMI | APIC_ICR_INT_MASK); /* NMI at LINT1 */
+       lapic_write (LAPIC_LINT1, val);
+}
+
+PRIVATE int lapic_enable_in_msr(void)
+{
+       u64_t msr;
+       u32_t addr;
+
+       ia32_msr_read(IA32_APIC_BASE, &msr.hi, &msr.lo);
+
+       /*
+        * FIXME if the location is different (unlikely) then the one we expect,
+        * update it
+        */
+       addr = (msr.lo >> 12) | ((msr.hi & 0xf) << 20);
+       if (phys2vir(addr) != (lapic_addr >> 12)) {
+               if (msr.hi & 0xf) {
+                       kprintf("ERROR : APIC address needs more then 32 bits\n");
+                       return 0;
+               }
+               lapic_addr = phys2vir(msr.lo & ~((1 << 12) - 1));
+       }
+
+       msr.lo |= (1 << IA32_APIC_BASE_ENABLE_BIT);
+       ia32_msr_write(IA32_APIC_BASE, msr.hi, msr.lo);
+
+       return 1;
+}
+
+PUBLIC int lapic_enable(void)
+{
+       u32_t val, nlvt;
+       u32_t timeout = 0xFFFF;
+       u32_t errstatus = 0;
+       int i;
+       unsigned cpu = cpuid ();
+
+       if (!lapic_addr)
+               return 0;
+
+       if (!lapic_enable_in_msr())
+               return 0;
+
+       lapic_eoi_addr = LAPIC_EOI;
+       /* clear error state register. */
+       val = lapic_errstatus ();
+
+       /* Enable Local APIC and set the spurious vector to 0xff. */
+
+       val = lapic_read(LAPIC_SIVR) & 0xFFFFFF00;
+       val |= (APIC_ENABLE | APIC_FOCUS | APIC_SPURIOUS_INT_VECTOR);
+       lapic_write(LAPIC_SIVR, val);
+       lapic_read(LAPIC_SIVR);
+
+       *((u32_t *)lapic_eoi_addr) = 0;
+
+       cpu = cpuid ();
+
+       /* Program Logical Destination Register. */
+       val = lapic_read(LAPIC_LDR) & ~0xFF000000;
+       val |= (cpu & 0xFF) << 24;
+       lapic_write(LAPIC_LDR, val);
+
+       /* Program Destination Format Register for Flat mode. */
+       val = lapic_read(LAPIC_DFR) | 0xF0000000;
+       lapic_write (LAPIC_DFR, val);
+
+       if (nlints == 0) {
+               lapic_enable_no_lints();
+       }
+
+       val = lapic_read (LAPIC_LVTER) & 0xFFFFFF00;
+       lapic_write (LAPIC_LVTER, val);
+
+       nlvt = (lapic_read(LAPIC_VERSION)>>16) & 0xFF;
+
+       if(nlvt >= 4) {
+               val = lapic_read(LAPIC_LVTTMR);
+               lapic_write(LAPIC_LVTTMR, val | APIC_ICR_INT_MASK);
+       }
+
+       if(nlvt >= 5) {
+               val = lapic_read(LAPIC_LVTPCR);
+               lapic_write(LAPIC_LVTPCR, val | APIC_ICR_INT_MASK);
+       }
+
+       /* setup TPR to allow all interrupts. */
+       val = lapic_read (LAPIC_TPR);
+       /* accept all interrupts */
+       lapic_write (LAPIC_TPR, val & ~0xFF);
+
+       lapic_read (LAPIC_SIVR);
+       *((u32_t *)lapic_eoi_addr) = 0;
+
+
+       cpu_has_tsc = _cpufeature(_CPUF_I386_TSC);
+       BOOT_VERBOSE(if (cpu_has_tsc) kprintf("CPU has Timestamp counter\n"));
+
+       apic_calibrate_clocks();
+       BOOT_VERBOSE(kprintf("APIC timer calibrated\n"));
+
+       return 1;
+}
+
+PRIVATE void apic_spurios_intr(void)
+{
+       kprintf("WARNING spurious interrupt\n");
+       for(;;);
+}
+
+PRIVATE struct gate_table_s gate_table_ioapic[] = {
+       { apic_hwint00, VECTOR( 0), INTR_PRIVILEGE },
+       { apic_hwint01, VECTOR( 1), INTR_PRIVILEGE },
+       { apic_hwint02, VECTOR( 2), INTR_PRIVILEGE },
+       { apic_hwint03, VECTOR( 3), INTR_PRIVILEGE },
+       { apic_hwint04, VECTOR( 4), INTR_PRIVILEGE },
+       { apic_hwint05, VECTOR( 5), INTR_PRIVILEGE },
+       { apic_hwint06, VECTOR( 6), INTR_PRIVILEGE },
+       { apic_hwint07, VECTOR( 7), INTR_PRIVILEGE },
+       { apic_hwint08, VECTOR( 8), INTR_PRIVILEGE },
+       { apic_hwint09, VECTOR( 9), INTR_PRIVILEGE },
+       { apic_hwint10, VECTOR(10), INTR_PRIVILEGE },
+       { apic_hwint11, VECTOR(11), INTR_PRIVILEGE },
+       { apic_hwint12, VECTOR(12), INTR_PRIVILEGE },
+       { apic_hwint13, VECTOR(13), INTR_PRIVILEGE },
+       { apic_hwint14, VECTOR(14), INTR_PRIVILEGE },
+       { apic_hwint15, VECTOR(15), INTR_PRIVILEGE },
+       { apic_spurios_intr, APIC_SPURIOUS_INT_VECTOR, INTR_PRIVILEGE },
+       { NULL, 0, 0}
+};
+
+PRIVATE struct gate_table_s gate_table_common[] = {
+       { syscall_entry, SYS386_VECTOR, USER_PRIVILEGE },
+       { level0_call, LEVEL0_VECTOR, TASK_PRIVILEGE },
+       { NULL, 0, 0}
+};
+
+#ifdef CONFIG_APIC_DEBUG
+PRIVATE lapic_set_dummy_handlers(void)
+{
+       char * handler;
+       int vect = 32;
+
+       handler = &lapic_intr_dummy_handles_start;
+       handler += vect * LAPIC_INTR_DUMMY_HANDLER_SIZE;
+       for(; handler < &lapic_intr_dummy_handles_end;
+                       handler += LAPIC_INTR_DUMMY_HANDLER_SIZE) {
+               int_gate(vect++, (vir_bytes) handler,
+                               PRESENT | INT_GATE_TYPE |
+                               (INTR_PRIVILEGE << DPL_SHIFT));
+       }
+}
+#endif
+
+/* Build descriptors for interrupt gates in IDT. */
+PUBLIC void apic_idt_init(int reset)
+{
+       /* Set up idt tables for smp mode.
+        */
+       vir_bytes local_timer_intr_handler;
+
+       if (reset) {
+               idt_copy_vectors(gate_table_pic);
+               idt_copy_vectors(gate_table_common);
+               return;
+       }
+
+#ifdef CONFIG_APIC_DEBUG
+       if (cpu_is_bsp(cpuid()))
+               kprintf("APIC debugging is enabled\n");
+       lapic_set_dummy_handlers();
+#endif
+
+       /* Build descriptors for interrupt gates in IDT. */
+       if (ioapic_enabled)
+               idt_copy_vectors(gate_table_ioapic);
+       else
+               idt_copy_vectors(gate_table_pic);
+
+       idt_copy_vectors(gate_table_common);
+
+       /* configure the timer interupt handler */
+       if (cpu_is_bsp(cpuid())) {
+               local_timer_intr_handler = (vir_bytes) lapic_bsp_timer_int_handler;
+               BOOT_VERBOSE(kprintf("Initiating BSP timer handler\n"));
+       } else {
+               local_timer_intr_handler = (vir_bytes) lapic_ap_timer_int_handler;
+               BOOT_VERBOSE(kprintf("Initiating AP timer handler\n"));
+       }
+
+       /* register the timer interrupt handler for this CPU */
+       int_gate(APIC_TIMER_INT_VECTOR, (vir_bytes) local_timer_intr_handler,
+               PRESENT | INT_GATE_TYPE | (INTR_PRIVILEGE << DPL_SHIFT));
+}
+
+PUBLIC int apic_single_cpu_init(void)
+{
+       if (!cpu_feature_apic_on_chip())
+               return 0;
+
+       lapic_addr = phys2vir(LOCAL_APIC_DEF_ADDR);
+       ioapic_enabled = 0;
+
+       if (!lapic_enable()) {
+               lapic_addr = 0x0;
+               return 0;
+       }
+
+       apic_idt_init(0); /* Not a reset ! */
+       idt_reload();
+       return 1;
+}
diff --git a/kernel/arch/i386/apic.h b/kernel/arch/i386/apic.h
new file mode 100644 (file)
index 0000000..fa7dde5
--- /dev/null
@@ -0,0 +1,105 @@
+#ifndef __APIC_H__
+#define __APIC_H__
+
+#define LOCAL_APIC_DEF_ADDR    0xfee00000 /* default local apic address */
+#define IO_APIC_DEF_ADDR       0xfec00000 /* default i/o apic address */
+
+#define LAPIC_ID       (lapic_addr + 0x020)
+#define LAPIC_VERSION  (lapic_addr + 0x030)
+#define LAPIC_TPR      (lapic_addr + 0x080)
+#define LAPIC_EOI      (lapic_addr + 0x0b0)
+#define LAPIC_LDR      (lapic_addr + 0x0d0)
+#define LAPIC_DFR      (lapic_addr + 0x0e0)
+#define LAPIC_SIVR     (lapic_addr + 0x0f0)
+#define LAPIC_ESR      (lapic_addr + 0x280)
+#define LAPIC_ICR1     (lapic_addr + 0x300)
+#define LAPIC_ICR2     (lapic_addr + 0x310)
+#define LAPIC_LVTTR    (lapic_addr + 0x320)
+#define LAPIC_LVTTMR   (lapic_addr + 0x330)
+#define LAPIC_LVTPCR   (lapic_addr + 0x340)
+#define LAPIC_LINT0    (lapic_addr + 0x350)
+#define LAPIC_LINT1    (lapic_addr + 0x360)
+#define LAPIC_LVTER    (lapic_addr + 0x370)
+#define LAPIC_TIMER_ICR        (lapic_addr + 0x380)
+#define LAPIC_TIMER_CCR        (lapic_addr + 0x390)
+#define LAPIC_TIMER_DCR        (lapic_addr + 0x3e0)
+
+#define IOAPIC_ID                      0x0
+#define IOAPIC_VERSION                 0x1
+#define IOAPIC_ARB                     0x2
+#define IOAPIC_REDIR_TABLE             0x10
+
+#define APIC_TIMER_INT_VECTOR          0xfe
+#define APIC_SPURIOUS_INT_VECTOR       0xff
+
+
+#ifndef __ASSEMBLY__
+
+#include "../../kernel.h"
+
+EXTERN int ioapic_enabled;
+EXTERN u32_t lapic_addr;
+EXTERN u32_t lapic_eoi_addr;
+EXTERN u32_t lapic_taskpri_addr;
+EXTERN int bsp_lapic_id;
+
+#define MAX_NR_IOAPICS                 32
+#define MAX_NR_BUSES                   32
+#define MAX_NR_APICIDS                 255
+#define MAX_NR_LCLINTS                 2
+
+EXTERN u8_t apicid2cpuid[MAX_NR_APICIDS+1];
+EXTERN unsigned apic_imcrp;
+EXTERN unsigned nioapics;
+EXTERN unsigned nbuses;
+EXTERN unsigned nintrs;
+EXTERN unsigned nlints;
+
+EXTERN u32_t ioapic_id_mask[8];
+EXTERN u32_t lapic_id_mask[8];
+EXTERN u32_t lapic_addr_vaddr; /* we remember the virtual address here until we
+                                 switch to paging */
+EXTERN u32_t lapic_addr;
+EXTERN u32_t lapic_eoi_addr;
+EXTERN u32_t lapic_taskpri_addr;
+
+_PROTOTYPE (void calc_bus_clock, (void));
+_PROTOTYPE (u32_t lapic_errstatus, (void));
+/*
+_PROTOTYPE (u32_t ioapic_read, (u32_t addr, u32_t offset));
+_PROTOTYPE (void ioapic_write, (u32_t addr, u32_t offset, u32_t data));
+_PROTOTYPE (void lapic_eoi, (void));
+*/
+_PROTOTYPE (void lapic_microsec_sleep, (unsigned count));
+_PROTOTYPE (void smp_ioapic_unmask, (void));
+_PROTOTYPE (void ioapic_disable_irqs, (u32_t irq));
+_PROTOTYPE (void ioapic_enable_irqs, (u32_t irq));
+_PROTOTYPE (u32_t ioapic_irqs_inuse, (void));
+_PROTOTYPE (void smp_recv_ipi, (int arg));
+_PROTOTYPE (void ioapic_config_pci_irq, (u32_t data));
+
+_PROTOTYPE (int lapic_enable, (void));
+_PROTOTYPE (void lapic_disable, (void));
+
+_PROTOTYPE (void ioapic_disable_all, (void));
+_PROTOTYPE (int ioapic_enable_all, (void));
+
+_PROTOTYPE(void apic_idt_init, (int reset));
+
+_PROTOTYPE(int apic_single_cpu_init, (void));
+
+_PROTOTYPE(void lapic_set_timer_periodic, (unsigned freq));
+_PROTOTYPE(void lapic_stop_timer, (void));
+
+#include <minix/cpufeature.h>
+
+#define cpu_feature_apic_on_chip() _cpufeature(_CPUF_I386_APIC_ON_CHIP)
+
+#define lapic_read(what)       (*((u32_t *)((char*)(what))))
+#define lapic_write(what, data)        do {                                    \
+       (*((u32_t *)((char*)(what)))) = data;                   \
+} while(0)
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __APIC_H__ */
diff --git a/kernel/arch/i386/apic_asm.S b/kernel/arch/i386/apic_asm.S
new file mode 100644 (file)
index 0000000..28c53b4
--- /dev/null
@@ -0,0 +1,447 @@
+#include <archconst.h>
+#include "apic.h"
+#include "sconst.h"
+#include "apic_asm.h"
+
+.globl apic_hwint00    /*  handlers for hardware interrupts */
+.globl apic_hwint01
+.globl apic_hwint02
+.globl apic_hwint03
+.globl apic_hwint04
+.globl apic_hwint05
+.globl apic_hwint06
+.globl apic_hwint07
+.globl apic_hwint08
+.globl apic_hwint09
+.globl apic_hwint10
+.globl apic_hwint11
+.globl apic_hwint12
+.globl apic_hwint13
+.globl apic_hwint14
+.globl apic_hwint15
+
+#define APIC_IRQ_HANDLER(irq)  \
+       push    $irq                                                            ;\
+       call    irq_handle              /* intr_handle(irq_handlers[irq]) */    ;\
+       add     $4, %esp                                                        ;\
+       mov     lapic_eoi_addr, %eax                                            ;\
+       movl    $0, (%eax)                                                      ;\
+
+/*===========================================================================*/
+/*                             interrupt handlers                           */
+/*             interrupt handlers for 386 32-bit protected mode             */
+/*             APIC interrupt handlers for 386 32-bit protected mode        */
+/*===========================================================================*/
+#define apic_hwint(irq) \
+       TEST_INT_IN_KERNEL(4, 0f)                                       ;\
+                                                                       \
+       SAVE_PROCESS_CTX(0)                                             ;\
+       movl    $0, %ebp        /* for stack trace */                   ;\
+       APIC_IRQ_HANDLER(irq)                                           ;\
+       jmp     restart                                                 ;\
+                                                                       \
+0:                                                                     \
+       pusha                                                           ;\
+       APIC_IRQ_HANDLER(irq)                                           ;\
+       popa                                                            ;\
+       iret                                                            ;
+
+/*  Each of these entry points is an expansion of the hwint_master macro */
+.balign        16
+apic_hwint00:
+/*  Interrupt routine for irq 0 (the clock). */
+       apic_hwint(0)
+
+.balign        16
+apic_hwint01:
+/*  Interrupt routine for irq 1 (keyboard) */
+       apic_hwint(1)
+
+.balign        16
+apic_hwint02:
+/*  Interrupt routine for irq 2 (cascade!) */
+       apic_hwint(2)
+
+.balign        16
+apic_hwint03:
+/*  Interrupt routine for irq 3 (second serial) */
+       apic_hwint(3)
+
+.balign        16
+apic_hwint04:
+/*  Interrupt routine for irq 4 (first serial) */
+       apic_hwint(4)
+
+.balign        16
+apic_hwint05:
+/*  Interrupt routine for irq 5 (XT winchester) */
+       apic_hwint(5)
+
+.balign        16
+apic_hwint06:
+/*  Interrupt routine for irq 6 (floppy) */
+       apic_hwint(6)
+
+.balign        16
+apic_hwint07:
+/*  Interrupt routine for irq 7 (printer) */
+       apic_hwint(7)
+
+.balign        16
+apic_hwint08:
+/*  Interrupt routine for irq 8 (realtime clock) */
+       apic_hwint(8)
+
+.balign        16
+apic_hwint09:
+/*  Interrupt routine for irq 9 (irq 2 redirected) */
+       apic_hwint(9)
+
+.balign        16
+apic_hwint10:
+/*  Interrupt routine for irq 10 */
+       apic_hwint(10)
+
+.balign        16
+apic_hwint11:
+/*  Interrupt routine for irq 11 */
+       apic_hwint(11)
+
+.balign        16
+apic_hwint12:
+/*  Interrupt routine for irq 12 */
+       apic_hwint(12)
+
+.balign        16
+apic_hwint13:
+/*  Interrupt routine for irq 13 (FPU exception) */
+       apic_hwint(13)
+
+.balign        16
+apic_hwint14:
+/*  Interrupt routine for irq 14 (AT winchester) */
+       apic_hwint(14)
+
+.balign        16
+apic_hwint15:
+/*  Interrupt routine for irq 15 */
+       apic_hwint(15)
+
+
+#define LAPIC_INTR_HANDLER(func)       \
+       movl    $func, %eax                                             ;\
+       call    *%eax           /* call the actual handler */           ;\
+       mov     lapic_eoi_addr, %eax    /* the end of handler*/         ;\
+       movl    $0, (%eax)                                              ;
+
+/*===========================================================================*/
+/*                     handler of the local APIC interrupts                 */
+/*===========================================================================*/
+
+#define lapic_intr(func) \
+       TEST_INT_IN_KERNEL(4, 0f)                                       ;\
+                                                                       \
+       SAVE_PROCESS_CTX(0)                                             ;\
+       movl    $0, %ebp                /* for stack trace */           ;\
+       LAPIC_INTR_HANDLER(func)                                        ;\
+       jmp     restart                                                 ;\
+       \
+0:     \
+       pusha                                                           ;\
+       LAPIC_INTR_HANDLER(func)                                        ;\
+       popa                                                            ;\
+       iret                                                            ;
+
+/* apic timer tick handlers */
+.globl lapic_bsp_timer_int_handler
+lapic_bsp_timer_int_handler:
+       lapic_intr(bsp_timer_int_handler)
+
+.globl lapic_ap_timer_int_handler
+lapic_ap_timer_int_handler:
+       lapic_intr(ap_timer_int_handler)
+
+#ifdef CONFIG_APIC_DEBUG
+
+.data
+lapic_intr_dummy_handler_msg:
+.ascii "UNHABLED APIC interrupt vector %d\n"
+
+.text
+
+#define lapic_intr_dummy_handler(vect)                 \
+       pushl   $vect;                                  \
+       push    $lapic_intr_dummy_handler_msg;          \
+       call    kprintf;                                \
+1:     jmp     1b; /* never return */
+
+#define LAPIC_INTR_DUMMY_HANDLER(vect)                 \
+       .balign LAPIC_INTR_DUMMY_HANDLER_SIZE;          \
+       lapic_intr_dummy_handler_##vect: lapic_intr_dummy_handler(vect)
+
+.globl lapic_intr_dummy_handles_start
+lapic_intr_dummy_handles_start:
+
+LAPIC_INTR_DUMMY_HANDLER(0)
+LAPIC_INTR_DUMMY_HANDLER(1)
+LAPIC_INTR_DUMMY_HANDLER(2)
+LAPIC_INTR_DUMMY_HANDLER(3)
+LAPIC_INTR_DUMMY_HANDLER(4)
+LAPIC_INTR_DUMMY_HANDLER(5)
+LAPIC_INTR_DUMMY_HANDLER(6)
+LAPIC_INTR_DUMMY_HANDLER(7)
+LAPIC_INTR_DUMMY_HANDLER(8)
+LAPIC_INTR_DUMMY_HANDLER(9)
+LAPIC_INTR_DUMMY_HANDLER(10)
+LAPIC_INTR_DUMMY_HANDLER(11)
+LAPIC_INTR_DUMMY_HANDLER(12)
+LAPIC_INTR_DUMMY_HANDLER(13)
+LAPIC_INTR_DUMMY_HANDLER(14)
+LAPIC_INTR_DUMMY_HANDLER(15)
+LAPIC_INTR_DUMMY_HANDLER(16)
+LAPIC_INTR_DUMMY_HANDLER(17)
+LAPIC_INTR_DUMMY_HANDLER(18)
+LAPIC_INTR_DUMMY_HANDLER(19)
+LAPIC_INTR_DUMMY_HANDLER(20)
+LAPIC_INTR_DUMMY_HANDLER(21)
+LAPIC_INTR_DUMMY_HANDLER(22)
+LAPIC_INTR_DUMMY_HANDLER(23)
+LAPIC_INTR_DUMMY_HANDLER(24)
+LAPIC_INTR_DUMMY_HANDLER(25)
+LAPIC_INTR_DUMMY_HANDLER(26)
+LAPIC_INTR_DUMMY_HANDLER(27)
+LAPIC_INTR_DUMMY_HANDLER(28)
+LAPIC_INTR_DUMMY_HANDLER(29)
+LAPIC_INTR_DUMMY_HANDLER(30)
+LAPIC_INTR_DUMMY_HANDLER(31)
+LAPIC_INTR_DUMMY_HANDLER(32)
+LAPIC_INTR_DUMMY_HANDLER(33)
+LAPIC_INTR_DUMMY_HANDLER(34)
+LAPIC_INTR_DUMMY_HANDLER(35)
+LAPIC_INTR_DUMMY_HANDLER(36)
+LAPIC_INTR_DUMMY_HANDLER(37)
+LAPIC_INTR_DUMMY_HANDLER(38)
+LAPIC_INTR_DUMMY_HANDLER(39)
+LAPIC_INTR_DUMMY_HANDLER(40)
+LAPIC_INTR_DUMMY_HANDLER(41)
+LAPIC_INTR_DUMMY_HANDLER(42)
+LAPIC_INTR_DUMMY_HANDLER(43)
+LAPIC_INTR_DUMMY_HANDLER(44)
+LAPIC_INTR_DUMMY_HANDLER(45)
+LAPIC_INTR_DUMMY_HANDLER(46)
+LAPIC_INTR_DUMMY_HANDLER(47)
+LAPIC_INTR_DUMMY_HANDLER(48)
+LAPIC_INTR_DUMMY_HANDLER(49)
+LAPIC_INTR_DUMMY_HANDLER(50)
+LAPIC_INTR_DUMMY_HANDLER(51)
+LAPIC_INTR_DUMMY_HANDLER(52)
+LAPIC_INTR_DUMMY_HANDLER(53)
+LAPIC_INTR_DUMMY_HANDLER(54)
+LAPIC_INTR_DUMMY_HANDLER(55)
+LAPIC_INTR_DUMMY_HANDLER(56)
+LAPIC_INTR_DUMMY_HANDLER(57)
+LAPIC_INTR_DUMMY_HANDLER(58)
+LAPIC_INTR_DUMMY_HANDLER(59)
+LAPIC_INTR_DUMMY_HANDLER(60)
+LAPIC_INTR_DUMMY_HANDLER(61)
+LAPIC_INTR_DUMMY_HANDLER(62)
+LAPIC_INTR_DUMMY_HANDLER(63)
+LAPIC_INTR_DUMMY_HANDLER(64)
+LAPIC_INTR_DUMMY_HANDLER(65)
+LAPIC_INTR_DUMMY_HANDLER(66)
+LAPIC_INTR_DUMMY_HANDLER(67)
+LAPIC_INTR_DUMMY_HANDLER(68)
+LAPIC_INTR_DUMMY_HANDLER(69)
+LAPIC_INTR_DUMMY_HANDLER(70)
+LAPIC_INTR_DUMMY_HANDLER(71)
+LAPIC_INTR_DUMMY_HANDLER(72)
+LAPIC_INTR_DUMMY_HANDLER(73)
+LAPIC_INTR_DUMMY_HANDLER(74)
+LAPIC_INTR_DUMMY_HANDLER(75)
+LAPIC_INTR_DUMMY_HANDLER(76)
+LAPIC_INTR_DUMMY_HANDLER(77)
+LAPIC_INTR_DUMMY_HANDLER(78)
+LAPIC_INTR_DUMMY_HANDLER(79)
+LAPIC_INTR_DUMMY_HANDLER(80)
+LAPIC_INTR_DUMMY_HANDLER(81)
+LAPIC_INTR_DUMMY_HANDLER(82)
+LAPIC_INTR_DUMMY_HANDLER(83)
+LAPIC_INTR_DUMMY_HANDLER(84)
+LAPIC_INTR_DUMMY_HANDLER(85)
+LAPIC_INTR_DUMMY_HANDLER(86)
+LAPIC_INTR_DUMMY_HANDLER(87)
+LAPIC_INTR_DUMMY_HANDLER(88)
+LAPIC_INTR_DUMMY_HANDLER(89)
+LAPIC_INTR_DUMMY_HANDLER(90)
+LAPIC_INTR_DUMMY_HANDLER(91)
+LAPIC_INTR_DUMMY_HANDLER(92)
+LAPIC_INTR_DUMMY_HANDLER(93)
+LAPIC_INTR_DUMMY_HANDLER(94)
+LAPIC_INTR_DUMMY_HANDLER(95)
+LAPIC_INTR_DUMMY_HANDLER(96)
+LAPIC_INTR_DUMMY_HANDLER(97)
+LAPIC_INTR_DUMMY_HANDLER(98)
+LAPIC_INTR_DUMMY_HANDLER(99)
+LAPIC_INTR_DUMMY_HANDLER(100)
+LAPIC_INTR_DUMMY_HANDLER(101)
+LAPIC_INTR_DUMMY_HANDLER(102)
+LAPIC_INTR_DUMMY_HANDLER(103)
+LAPIC_INTR_DUMMY_HANDLER(104)
+LAPIC_INTR_DUMMY_HANDLER(105)
+LAPIC_INTR_DUMMY_HANDLER(106)
+LAPIC_INTR_DUMMY_HANDLER(107)
+LAPIC_INTR_DUMMY_HANDLER(108)
+LAPIC_INTR_DUMMY_HANDLER(109)
+LAPIC_INTR_DUMMY_HANDLER(110)
+LAPIC_INTR_DUMMY_HANDLER(111)
+LAPIC_INTR_DUMMY_HANDLER(112)
+LAPIC_INTR_DUMMY_HANDLER(113)
+LAPIC_INTR_DUMMY_HANDLER(114)
+LAPIC_INTR_DUMMY_HANDLER(115)
+LAPIC_INTR_DUMMY_HANDLER(116)
+LAPIC_INTR_DUMMY_HANDLER(117)
+LAPIC_INTR_DUMMY_HANDLER(118)
+LAPIC_INTR_DUMMY_HANDLER(119)
+LAPIC_INTR_DUMMY_HANDLER(120)
+LAPIC_INTR_DUMMY_HANDLER(121)
+LAPIC_INTR_DUMMY_HANDLER(122)
+LAPIC_INTR_DUMMY_HANDLER(123)
+LAPIC_INTR_DUMMY_HANDLER(124)
+LAPIC_INTR_DUMMY_HANDLER(125)
+LAPIC_INTR_DUMMY_HANDLER(126)
+LAPIC_INTR_DUMMY_HANDLER(127)
+LAPIC_INTR_DUMMY_HANDLER(128)
+LAPIC_INTR_DUMMY_HANDLER(129)
+LAPIC_INTR_DUMMY_HANDLER(130)
+LAPIC_INTR_DUMMY_HANDLER(131)
+LAPIC_INTR_DUMMY_HANDLER(132)
+LAPIC_INTR_DUMMY_HANDLER(133)
+LAPIC_INTR_DUMMY_HANDLER(134)
+LAPIC_INTR_DUMMY_HANDLER(135)
+LAPIC_INTR_DUMMY_HANDLER(136)
+LAPIC_INTR_DUMMY_HANDLER(137)
+LAPIC_INTR_DUMMY_HANDLER(138)
+LAPIC_INTR_DUMMY_HANDLER(139)
+LAPIC_INTR_DUMMY_HANDLER(140)
+LAPIC_INTR_DUMMY_HANDLER(141)
+LAPIC_INTR_DUMMY_HANDLER(142)
+LAPIC_INTR_DUMMY_HANDLER(143)
+LAPIC_INTR_DUMMY_HANDLER(144)
+LAPIC_INTR_DUMMY_HANDLER(145)
+LAPIC_INTR_DUMMY_HANDLER(146)
+LAPIC_INTR_DUMMY_HANDLER(147)
+LAPIC_INTR_DUMMY_HANDLER(148)
+LAPIC_INTR_DUMMY_HANDLER(149)
+LAPIC_INTR_DUMMY_HANDLER(150)
+LAPIC_INTR_DUMMY_HANDLER(151)
+LAPIC_INTR_DUMMY_HANDLER(152)
+LAPIC_INTR_DUMMY_HANDLER(153)
+LAPIC_INTR_DUMMY_HANDLER(154)
+LAPIC_INTR_DUMMY_HANDLER(155)
+LAPIC_INTR_DUMMY_HANDLER(156)
+LAPIC_INTR_DUMMY_HANDLER(157)
+LAPIC_INTR_DUMMY_HANDLER(158)
+LAPIC_INTR_DUMMY_HANDLER(159)
+LAPIC_INTR_DUMMY_HANDLER(160)
+LAPIC_INTR_DUMMY_HANDLER(161)
+LAPIC_INTR_DUMMY_HANDLER(162)
+LAPIC_INTR_DUMMY_HANDLER(163)
+LAPIC_INTR_DUMMY_HANDLER(164)
+LAPIC_INTR_DUMMY_HANDLER(165)
+LAPIC_INTR_DUMMY_HANDLER(166)
+LAPIC_INTR_DUMMY_HANDLER(167)
+LAPIC_INTR_DUMMY_HANDLER(168)
+LAPIC_INTR_DUMMY_HANDLER(169)
+LAPIC_INTR_DUMMY_HANDLER(170)
+LAPIC_INTR_DUMMY_HANDLER(171)
+LAPIC_INTR_DUMMY_HANDLER(172)
+LAPIC_INTR_DUMMY_HANDLER(173)
+LAPIC_INTR_DUMMY_HANDLER(174)
+LAPIC_INTR_DUMMY_HANDLER(175)
+LAPIC_INTR_DUMMY_HANDLER(176)
+LAPIC_INTR_DUMMY_HANDLER(177)
+LAPIC_INTR_DUMMY_HANDLER(178)
+LAPIC_INTR_DUMMY_HANDLER(179)
+LAPIC_INTR_DUMMY_HANDLER(180)
+LAPIC_INTR_DUMMY_HANDLER(181)
+LAPIC_INTR_DUMMY_HANDLER(182)
+LAPIC_INTR_DUMMY_HANDLER(183)
+LAPIC_INTR_DUMMY_HANDLER(184)
+LAPIC_INTR_DUMMY_HANDLER(185)
+LAPIC_INTR_DUMMY_HANDLER(186)
+LAPIC_INTR_DUMMY_HANDLER(187)
+LAPIC_INTR_DUMMY_HANDLER(188)
+LAPIC_INTR_DUMMY_HANDLER(189)
+LAPIC_INTR_DUMMY_HANDLER(190)
+LAPIC_INTR_DUMMY_HANDLER(191)
+LAPIC_INTR_DUMMY_HANDLER(192)
+LAPIC_INTR_DUMMY_HANDLER(193)
+LAPIC_INTR_DUMMY_HANDLER(194)
+LAPIC_INTR_DUMMY_HANDLER(195)
+LAPIC_INTR_DUMMY_HANDLER(196)
+LAPIC_INTR_DUMMY_HANDLER(197)
+LAPIC_INTR_DUMMY_HANDLER(198)
+LAPIC_INTR_DUMMY_HANDLER(199)
+LAPIC_INTR_DUMMY_HANDLER(200)
+LAPIC_INTR_DUMMY_HANDLER(201)
+LAPIC_INTR_DUMMY_HANDLER(202)
+LAPIC_INTR_DUMMY_HANDLER(203)
+LAPIC_INTR_DUMMY_HANDLER(204)
+LAPIC_INTR_DUMMY_HANDLER(205)
+LAPIC_INTR_DUMMY_HANDLER(206)
+LAPIC_INTR_DUMMY_HANDLER(207)
+LAPIC_INTR_DUMMY_HANDLER(208)
+LAPIC_INTR_DUMMY_HANDLER(209)
+LAPIC_INTR_DUMMY_HANDLER(210)
+LAPIC_INTR_DUMMY_HANDLER(211)
+LAPIC_INTR_DUMMY_HANDLER(212)
+LAPIC_INTR_DUMMY_HANDLER(213)
+LAPIC_INTR_DUMMY_HANDLER(214)
+LAPIC_INTR_DUMMY_HANDLER(215)
+LAPIC_INTR_DUMMY_HANDLER(216)
+LAPIC_INTR_DUMMY_HANDLER(217)
+LAPIC_INTR_DUMMY_HANDLER(218)
+LAPIC_INTR_DUMMY_HANDLER(219)
+LAPIC_INTR_DUMMY_HANDLER(220)
+LAPIC_INTR_DUMMY_HANDLER(221)
+LAPIC_INTR_DUMMY_HANDLER(222)
+LAPIC_INTR_DUMMY_HANDLER(223)
+LAPIC_INTR_DUMMY_HANDLER(224)
+LAPIC_INTR_DUMMY_HANDLER(225)
+LAPIC_INTR_DUMMY_HANDLER(226)
+LAPIC_INTR_DUMMY_HANDLER(227)
+LAPIC_INTR_DUMMY_HANDLER(228)
+LAPIC_INTR_DUMMY_HANDLER(229)
+LAPIC_INTR_DUMMY_HANDLER(230)
+LAPIC_INTR_DUMMY_HANDLER(231)
+LAPIC_INTR_DUMMY_HANDLER(232)
+LAPIC_INTR_DUMMY_HANDLER(233)
+LAPIC_INTR_DUMMY_HANDLER(234)
+LAPIC_INTR_DUMMY_HANDLER(235)
+LAPIC_INTR_DUMMY_HANDLER(236)
+LAPIC_INTR_DUMMY_HANDLER(237)
+LAPIC_INTR_DUMMY_HANDLER(238)
+LAPIC_INTR_DUMMY_HANDLER(239)
+LAPIC_INTR_DUMMY_HANDLER(240)
+LAPIC_INTR_DUMMY_HANDLER(241)
+LAPIC_INTR_DUMMY_HANDLER(242)
+LAPIC_INTR_DUMMY_HANDLER(243)
+LAPIC_INTR_DUMMY_HANDLER(244)
+LAPIC_INTR_DUMMY_HANDLER(245)
+LAPIC_INTR_DUMMY_HANDLER(246)
+LAPIC_INTR_DUMMY_HANDLER(247)
+LAPIC_INTR_DUMMY_HANDLER(248)
+LAPIC_INTR_DUMMY_HANDLER(249)
+LAPIC_INTR_DUMMY_HANDLER(250)
+LAPIC_INTR_DUMMY_HANDLER(251)
+LAPIC_INTR_DUMMY_HANDLER(252)
+LAPIC_INTR_DUMMY_HANDLER(253)
+LAPIC_INTR_DUMMY_HANDLER(254)
+LAPIC_INTR_DUMMY_HANDLER(255)
+
+.globl lapic_intr_dummy_handles_end
+lapic_intr_dummy_handles_end:
+
+
+#endif /* CONFIG_APIC_DEBUG */
+
diff --git a/kernel/arch/i386/apic_asm.h b/kernel/arch/i386/apic_asm.h
new file mode 100644 (file)
index 0000000..f151606
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef __APIC_ASM_H__
+#define __APIC_ASM_H__
+
+
+#ifndef __ASSEMBLY__
+#include "../../kernel.h"
+
+_PROTOTYPE( void apic_hwint00, (void) );
+_PROTOTYPE( void apic_hwint01, (void) );
+_PROTOTYPE( void apic_hwint02, (void) );
+_PROTOTYPE( void apic_hwint03, (void) );
+_PROTOTYPE( void apic_hwint04, (void) );
+_PROTOTYPE( void apic_hwint05, (void) );
+_PROTOTYPE( void apic_hwint06, (void) );
+_PROTOTYPE( void apic_hwint07, (void) );
+_PROTOTYPE( void apic_hwint08, (void) );
+_PROTOTYPE( void apic_hwint09, (void) );
+_PROTOTYPE( void apic_hwint10, (void) );
+_PROTOTYPE( void apic_hwint11, (void) );
+_PROTOTYPE( void apic_hwint12, (void) );
+_PROTOTYPE( void apic_hwint13, (void) );
+_PROTOTYPE( void apic_hwint14, (void) );
+_PROTOTYPE( void apic_hwint15, (void) );
+
+/* The local APIC timer tick handlers */
+_PROTOTYPE(void lapic_bsp_timer_int_handler, (void));
+_PROTOTYPE(void lapic_ap_timer_int_handler, (void));
+
+#endif
+
+#define CONFIG_APIC_DEBUG
+
+#ifdef CONFIG_APIC_DEBUG
+
+#define LAPIC_INTR_DUMMY_HANDLER_SIZE  32
+
+#ifndef __ASSEMBLY__
+EXTERN char lapic_intr_dummy_handles_start;
+EXTERN char lapic_intr_dummy_handles_end;
+#endif
+
+#endif /* CONFIG_APIC_DEBUG */
+
+#endif /* __APIC_ASM_H__ */
index f5e456dc2e40ad772e5add8081d5b63a55745e5c..9cf0e7219db8694902d0bcc6422df02f374b170b 100644 (file)
@@ -8,6 +8,10 @@
 
 #include "../../clock.h"
 
+#ifdef CONFIG_APIC
+#include "apic.h"
+#endif
+
 #define CLOCK_ACK_BIT   0x80    /* PS/2 clock interrupt acknowledge bit */
 
 /* Clock parameters. */
@@ -69,24 +73,49 @@ PUBLIC clock_t read_8253A_timer(void)
 
 PUBLIC int arch_init_local_timer(unsigned freq)
 {
-       init_8253A_timer(freq);
+#ifdef CONFIG_APIC
+       /* if we know the address, lapic is enabled and we should use it */
+       if (lapic_addr) {
+               lapic_set_timer_periodic(freq);
+       } else
+       {
+               BOOT_VERBOSE(kprintf("Initiating legacy i8253 timer\n"));
+#else
+       {
+#endif
+               init_8253A_timer(freq);
+       }
 
        return 0;
 }
 
 PUBLIC void arch_stop_local_timer(void)
 {
-       stop_8253A_timer();
+#ifdef CONFIG_APIC
+       if (lapic_addr) {
+               lapic_stop_timer();
+       } else
+#endif
+       {
+               stop_8253A_timer();
+       }
 }
 
 PUBLIC int arch_register_local_timer_handler(irq_handler_t handler)
 {
-       /* Using PIC, Initialize the CLOCK's interrupt hook. */
-       pic_timer_hook.proc_nr_e = NONE;
-
-       put_irq_handler(&pic_timer_hook, CLOCK_IRQ, handler);
-       put_irq_handler(&pic_timer_hook, CLOCK_IRQ,
-                       (irq_handler_t)bsp_timer_int_handler);
+#ifdef CONFIG_APIC
+       if (lapic_addr) {
+               /* Using APIC, it is configured in apic_idt_init() */
+               BOOT_VERBOSE(kprintf("Using LAPIC timer as tick source\n"));
+       } else
+#endif
+       {
+               /* Using PIC, Initialize the CLOCK's interrupt hook. */
+               pic_timer_hook.proc_nr_e = NONE;
+               pic_timer_hook.irq = CLOCK_IRQ;
+
+               put_irq_handler(&pic_timer_hook, CLOCK_IRQ, handler);
+       }
 
        return 0;
 }
diff --git a/kernel/arch/i386/glo.h b/kernel/arch/i386/glo.h
new file mode 100644 (file)
index 0000000..d056d5c
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __GLO_X86_H__
+#define __GLO_X86_H__
+
+EXTERN int cpu_has_tsc;        /* signal whether this cpu has time stamp register. This
+                          feature was introduced by Pentium */
+
+#endif /* __GLO_X86_H__ */
index 19ed4ed262ed8ed8e6a9b547fd34280182f23180..9f63b04bccf1c9853ba95170e2d15a50f0c36193 100644 (file)
 #define ICW4_AT_MASTER  0x05   /* not SFNM, not buffered, normal EOI, 8086 */
 #define ICW4_PC_SLAVE   0x09   /* not SFNM, buffered, normal EOI, 8086 */
 #define ICW4_PC_MASTER  0x0D   /* not SFNM, buffered, normal EOI, 8086 */
+#define ICW4_AT_AEOI_SLAVE   0x03 /* not SFNM, not buffered, auto EOI, 8086 */
+#define ICW4_AT_AEOI_MASTER  0x07 /* not SFNM, not buffered, auto EOI, 8086 */
+#define ICW4_PC_AEOI_SLAVE   0x0B /* not SFNM, buffered, auto EOI, 8086 */
+#define ICW4_PC_AEOI_MASTER  0x0F /* not SFNM, buffered, auto EOI, 8086 */
 
 #define set_vec(nr, addr)      ((void)0)
 
 /*===========================================================================*
  *                             intr_init                                    *
  *===========================================================================*/
-PUBLIC int intr_init(mine)
-int mine;
+PUBLIC int intr_init(int mine, int auto_eoi)
 {
 /* Initialize the 8259s, finishing with all interrupts disabled.  This is
  * only done in protected mode, in real mode we don't touch the 8259s, but
@@ -35,24 +38,31 @@ int mine;
  */
   int i;
 
-  intr_disable();
+  if (!intr_disabled())
+         intr_disable();
 
       /* The AT and newer PS/2 have two interrupt controllers, one master,
        * one slaved at IRQ 2.  (We don't have to deal with the PC that
        * has just one controller, because it must run in real mode.)
        */
       outb( INT_CTL, machine.ps_mca ? ICW1_PS : ICW1_AT);
-      outb( INT_CTLMASK, mine ? IRQ0_VECTOR : BIOS_IRQ0_VEC);
+      outb( INT_CTLMASK, mine == INTS_MINIX ? IRQ0_VECTOR : BIOS_IRQ0_VEC);
                                        /* ICW2 for master */
       outb( INT_CTLMASK, (1 << CASCADE_IRQ));
                                        /* ICW3 tells slaves */
-      outb( INT_CTLMASK, ICW4_AT_MASTER);
+      if (auto_eoi)
+          outb( INT_CTLMASK, ICW4_AT_AEOI_MASTER);
+      else
+          outb( INT_CTLMASK, ICW4_AT_MASTER);
       outb( INT_CTLMASK, ~(1 << CASCADE_IRQ)); /* IRQ 0-7 mask */
       outb( INT2_CTL, machine.ps_mca ? ICW1_PS : ICW1_AT);
-      outb( INT2_CTLMASK, mine ? IRQ8_VECTOR : BIOS_IRQ8_VEC);
+      outb( INT2_CTLMASK, mine == INTS_MINIX ? IRQ8_VECTOR : BIOS_IRQ8_VEC);
                                                /* ICW2 for slave */
       outb( INT2_CTLMASK, CASCADE_IRQ);        /* ICW3 is slave nr */
-      outb( INT2_CTLMASK, ICW4_AT_SLAVE);
+      if (auto_eoi)
+         outb( INT2_CTLMASK, ICW4_AT_AEOI_SLAVE);
+      else
+         outb( INT2_CTLMASK, ICW4_AT_SLAVE);
       outb( INT2_CTLMASK, ~0);         /* IRQ 8-15 mask */
 
       /* Copy the BIOS vectors from the BIOS to the Minix location, so we
@@ -81,7 +91,6 @@ PUBLIC int intr_disabled(void)
 PUBLIC void irq_8259_unmask(int irq)
 {
        unsigned ctl_mask = irq < 8 ? INT_CTLMASK : INT2_CTLMASK;
-
        outb(ctl_mask, inb(ctl_mask) & ~(1 << (irq & 0x7)));
 }
 
@@ -90,3 +99,12 @@ PUBLIC void irq_8259_mask(int irq)
        unsigned ctl_mask = irq < 8 ? INT_CTLMASK : INT2_CTLMASK;
        outb(ctl_mask, inb(ctl_mask) | (1 << (irq & 0x7)));
 }
+
+/* Disable 8259 - write 0xFF in OCW1 master and slave. */
+PUBLIC void i8259_disable(void)
+{
+       outb(INT2_CTLMASK, 0xFF);
+       outb(INT_CTLMASK, 0xFF);
+       inb(INT_CTLMASK);
+}
+
index 0bf7a3cbd825a19e13daac9af25d94babfeb028f..137d6aae94248a1f171e685e8622bbb05adc6792 100644 (file)
@@ -12,7 +12,7 @@
 /* Table sizes. */
 #define GDT_SIZE (FIRST_LDT_INDEX + NR_TASKS + NR_PROCS) 
                                        /* spec. and LDT's */
-#define IDT_SIZE (IRQ8_VECTOR + 8)     /* only up to the highest vector */
+#define IDT_SIZE 256   /* the table is set to it's maximal size */
 
 /* Fixed global descriptors.  1 to 7 are prescribed by the BIOS. */
 #define GDT_INDEX            1 /* GDT descriptor */
 #define INT_286_GATE         6 /* interrupt gate, used for all vectors */
 #define TRAP_286_GATE        7 /* not used */
 
+#define INT_GATE_TYPE  (INT_286_GATE | DESC_386_BIT)
+#define TSS_TYPE       (AVL_286_TSS  | DESC_386_BIT)
+
+
 /* Extra 386 hardware constants. */
 
 /* Exception vector numbers. */
 #define vir2phys(vir)   (kinfo.data_base + (vir_bytes) (vir))
 #define phys2vir(ph)   ((vir_bytes) (ph) - kinfo.data_base)
 
+#define INTEL_CPUID_GEN_EBX    0x756e6547 /* ASCII value of "Genu" */
+#define INTEL_CPUID_GEN_EDX    0x49656e69 /* ASCII value of "ineI" */
+#define INTEL_CPUID_GEN_ECX    0x6c65746e /* ASCII value of "ntel" */
+
+#define AMD_CPUID_GEN_EBX      0x68747541 /* ASCII value of "Auth" */
+#define AMD_CPUID_GEN_EDX      0x69746e65 /* ASCII value of "enti" */
+#define AMD_CPUID_GEN_ECX      0x444d4163 /* ASCII value of "cAMD" */
+
+
+
 #endif /* _I386_ACONST_H */
index 944c590a938a1708cc7ec5b73b73a05634903754..bb74790bfa6865af6e55f0f769203bd1097702f8 100644 (file)
@@ -45,6 +45,7 @@
 .globl read_ds
 .globl  read_cs
 .globl read_ss
+.globl idt_reload      /* reload idt when returning to monitor. */
 
 /*
  * The routines only guarantee to preserve the registers the C compiler 
@@ -144,15 +145,44 @@ csinit:
        mov     %ax, %ss
        xchgl   mon_sp, %esp    /* unswitch stacks */
        lidt    gdt+IDT_SELECTOR        /* reload interrupt descriptor table */
-       andb    $~0x02, gdt+TSS_SELECTOR+DESC_ACCESS    /* clear TSS busy bit */
-       mov     $TSS_SELECTOR, %eax
-       ltr     %ax     /* set TSS register */
+
+#ifdef CONFIG_APIC
+       cmpl    $0x0, lapic_addr
+       jne     3f
+       mov     $0, %ebx
+       jmp     4f
+
+3:
+       mov     $FLAT_DS_SELECTOR, %ebx
+       mov     %bx, %fs
+       movl    lapic_addr, %eax
+       add     $0x20, %eax
+       .byte 0x64; mov (%eax), %ebx
+       and     $0xFF000000, %ebx
+       shr     $24, %ebx
+       movzb   %bl, %ebx
+
+4:
+       add     $apicid2cpuid, %ebx
+       movzb   (%ebx), %eax
+       shl     $3, %eax
+       mov     %eax, %ebx
+       add     $TSS_SELECTOR, %eax
+       addl    gdt+DESC_ACCESS, %eax
+       and     $~0x02, %eax
+       ltr     %bx     /* set TSS register */
+
+       mov     $DS_SELECTOR, %eax
+       mov     %ax, %fs
+
+#endif /* CONFIG_APIC */
 
        pop     %eax
        outb    $INT_CTLMASK    /* restore interrupt masks */
        movb    %ah, %al
        outb    $INT2_CTLMASK
 
+6:
        addl    %ecx, lost_ticks        /* record lost clock ticks */
 
        popf    /* restore flags */
@@ -487,7 +517,7 @@ level0:
 read_cpu_flags:
        pushf
        mov     (%esp), %eax
-       popf
+       add     $4, %esp
        ret
 
 read_ds:
@@ -572,3 +602,62 @@ getcr3val:
        mov     %eax, thecr3
        ret
 
+/*
+ * Read the Model Specific Register (MSR) of IA32 architecture
+ *
+ * void ia32_msr_read(u32_t reg, u32_t * hi, u32_t * lo)
+ */
+.globl ia32_msr_read
+ia32_msr_read:
+       push    %ebp
+       mov     %esp, %ebp
+
+       mov     8(%ebp), %ecx
+       rdmsr
+       mov     12(%ebp), %ecx
+       mov     %edx, (%ecx)
+       mov     16(%ebp), %ecx
+       mov     %eax, (%ecx)
+
+       pop     %ebp
+       ret
+
+/*
+ * Write the Model Specific Register (MSR) of IA32 architecture
+ *
+ * void ia32_msr_write(u32_t reg, u32_t hi, u32_t lo)
+ */
+.globl ia32_msr_write
+ia32_msr_write:
+       push    %ebp
+       mov     %esp, %ebp
+
+       mov     12(%ebp), %edx
+       mov     16(%ebp), %eax
+       mov     8(%ebp), %ecx
+       wrmsr
+
+       pop     %ebp
+       ret
+
+/*===========================================================================*/
+/*                           idt_reload                                     */
+/*===========================================================================*/
+/*  PUBLIC void idt_reload (void); */
+.balign        16
+idt_reload:
+       lidt    gdt+IDT_SELECTOR        /*  reload interrupt descriptor table */
+       ret
+
+/*
+ * void reload_segment_regs(void)
+ */
+
+#define RELOAD_SEG_REG(reg)    \
+       mov     reg, %ax        ;\
+       mov     %ax, reg        ;
+
+.globl reload_ds
+reload_ds:
+       RELOAD_SEG_REG(%ds)
+       ret
index c11b5c11d54abadbf7c51e3af4b0e9728f6d260d..312d6abc9566a4bf322845d3552595a803daa812 100644 (file)
 #include "../../proto.h"
 #include "../../debug.h"
 
+#ifdef CONFIG_APIC
+#include "apic.h"
+#endif
+
 PRIVATE int psok = 0;
 
 #define PROCPDEPTR(pr, pi) ((u32_t *) ((u8_t *) vm_pagedirs +\
@@ -53,7 +57,6 @@ PUBLIC void vm_init(struct proc *newptproc)
 
 }
 
-
 #define TYPEDIRECT     0
 #define TYPEPROCMAP    1
 #define TYPEPHYS       2
@@ -1031,16 +1034,40 @@ void i386_freepde(int pde)
 
 PUBLIC arch_phys_map(int index, phys_bytes *addr, phys_bytes *len, int *flags)
 {
+#ifdef CONFIG_APIC
+       /* map the local APIC if enabled */
+       if (index == 0 && lapic_addr) {
+               *addr = vir2phys(lapic_addr);
+               *len = 4 << 10 /* 4kB */;
+               *flags = VMMF_UNCACHED;
+               return OK;
+       }
+       return EINVAL;
+#else
        /* we don't want anything */
        return EINVAL;
+#endif
 }
 
 PUBLIC arch_phys_map_reply(int index, vir_bytes addr)
 {
+#ifdef CONFIG_APIC
+       /* if local APIC is enabled */
+       if (index == 0 && lapic_addr) {
+               lapic_addr_vaddr = addr;
+       }
+#endif
        return OK;
 }
 
 PUBLIC int arch_enable_paging(void)
 {
+#ifdef CONFIG_APIC
+       /* if local APIC is enabled */
+       if (lapic_addr) {
+               lapic_addr = lapic_addr_vaddr;
+               lapic_eoi_addr = LAPIC_EOI;
+       }
+#endif
        return OK;
 }
index 29870b96c5d99a744313d273d8b46f39b60f48ee..30f6597f247ebec51e39516de7d7ad923fbf64d3 100644 (file)
@@ -29,8 +29,6 @@ PUBLIC struct segdesc_s gdt[GDT_SIZE];                /* used in klib.s and mpx.s */
 PRIVATE struct gatedesc_s idt[IDT_SIZE];       /* zero-init so none present */
 PUBLIC struct tss_s tss;                       /* zero init */
 
-FORWARD _PROTOTYPE( void int_gate, (unsigned vec_nr, vir_bytes offset,
-               unsigned dpl_type) );
 FORWARD _PROTOTYPE( void sdesc, (struct segdesc_s *segdp, phys_bytes base,
                vir_bytes size) );
 
@@ -141,6 +139,11 @@ PUBLIC void prot_init(void)
        minix_panic("kinfo.data_base not aligned", NO_NUM);
   kinfo.data_size = ((kinfo.data_size+CLICK_SIZE-1)/CLICK_SIZE) * CLICK_SIZE;
 
+  /* Click-round kernel. */
+  if(kinfo.data_base % CLICK_SIZE)
+       minix_panic("kinfo.data_base not aligned", NO_NUM);
+  kinfo.data_size = ((kinfo.data_size+CLICK_SIZE-1)/CLICK_SIZE) * CLICK_SIZE;
+
   /* Build gdt and idt pointers in GDT where the BIOS expects them. */
   dtp= (struct desctableptr_s *) &gdt[GDT_INDEX];
   * (u16_t *) dtp->limit = (sizeof gdt) - 1;
@@ -250,7 +253,7 @@ vir_bytes size;
 /*===========================================================================*
  *                             int_gate                                     *
  *===========================================================================*/
-PRIVATE void int_gate(vec_nr, offset, dpl_type)
+PUBLIC void int_gate(vec_nr, offset, dpl_type)
 unsigned vec_nr;
 vir_bytes offset;
 unsigned dpl_type;
@@ -460,6 +463,7 @@ PUBLIC int prot_set_kern_seg_limit(vir_bytes limit)
                        continue;
                rp->p_memmap[S].mem_len += incr_clicks;
                alloc_segments(rp);
+               rp->p_memmap[S].mem_len -= incr_clicks;
        }
 
        return OK;
index 24cc63f95af073dc0b230e7e46765bea632fce7d..08828a337b3f0e24d2e11a6a6c71144ce8f34e30 100644 (file)
@@ -80,7 +80,10 @@ _PROTOTYPE( void phys_outsb, (U16_t port, phys_bytes buf, size_t count) );
 _PROTOTYPE( void phys_outsw, (U16_t port, phys_bytes buf, size_t count) );
 _PROTOTYPE( u32_t read_cr3, (void) );
 _PROTOTYPE( void reload_cr3, (void) );
-_PROTOTYPE( void phys_memset, (phys_bytes ph, u32_t c, phys_bytes bytes)       );
+_PROTOTYPE( void phys_memset, (phys_bytes ph, u32_t c, phys_bytes bytes));
+_PROTOTYPE( void reload_ds, (void)                                     );
+_PROTOTYPE( void ia32_msr_read, (u32_t reg, u32_t * hi, u32_t * lo)    );
+_PROTOTYPE( void ia32_msr_write, (u32_t reg, u32_t hi, u32_t lo)       );
 
 /* protect.c */
 struct tss_s {
@@ -140,10 +143,14 @@ EXTERN struct gate_table_s gate_table_pic[];
 
 /* copies an array of vectors to the IDT. The last vector must be zero filled */
 _PROTOTYPE(void idt_copy_vectors, (struct gate_table_s * first));
+_PROTOTYPE(void idt_reload, (void));
 
 EXTERN void * k_boot_stktop;
 _PROTOTYPE(void tss_init, (struct tss_s * tss, void * kernel_stack, unsigned cpu));
 
+_PROTOTYPE( void int_gate, (unsigned vec_nr, vir_bytes offset,
+               unsigned dpl_type) );
+_PROTOTYPE(void i8259_disable, (void));
 
 /* functions defined in architecture-independent kernel source. */
 #include "../../proto.h"
index 2dbaa0163230c52555ffdd2a0e54501f274882e1..09ee7d9890be7676a30bb0451897411c72cfedf6 100644 (file)
        mov     %esi, %ss:BPREG(%ebp)                   ;\
                                                        \
        RESTORE_KERNEL_SEGS                             ;\
-       SAVE_TRAP_CTX(displ, %ebp, %esi)                ;\
-                                                       ;
+       SAVE_TRAP_CTX(displ, %ebp, %esi)                ;
 
 #endif /* __SCONST_H__ */
index dc0a12e83e1dcc5349249f90ef42e3c9b8c1ef08..426c53dc6ea8258efd931c15a135d5ef636ce501 100644 (file)
 #include "../../proc.h"
 #include "../../debug.h"
 
+#ifdef CONFIG_APIC
+#include "apic.h"
+#endif
+
 #define CR0_EM 0x0004          /* set to enable trap on any FP instruction */
 
 FORWARD _PROTOTYPE( void ser_debug, (int c));
@@ -25,6 +29,8 @@ PUBLIC void arch_monitor(void)
        level0(monitor);
 }
 
+PUBLIC int cpu_has_tsc;
+
 PUBLIC void arch_shutdown(int how)
 {
        /* Mask all interrupts, including the clock. */
@@ -125,14 +131,34 @@ PUBLIC void tss_init(struct tss_s * tss, void * kernel_stack, unsigned cpu)
 
 PUBLIC void arch_init(void)
 {
+#ifdef CONFIG_APIC
+       /*
+        * this is setting kernel segments to cover most of the phys memory. The
+        * value is high enough to reach local APIC nad IOAPICs before paging is
+        * turned on.
+        */
+       prot_set_kern_seg_limit(0xfff00000);
+       reload_ds();
+#endif
+
        idt_init();
 
        tss_init(&tss, &k_boot_stktop, 0);
 
+#if defined(CONFIG_APIC) && !defined(CONFIG_SMP)
+       if (config_no_apic) {
+               BOOT_VERBOSE(kprintf("APIC disabled, using legacy PIC\n"));
+       }
+       else if (!apic_single_cpu_init()) {
+               BOOT_VERBOSE(kprintf("APIC not present, using legacy PIC\n"));
+       }
+#endif
+
 #if 0
        /* Set CR0_EM until we get FP context switching */
        write_cr0(read_cr0() | CR0_EM);
 #endif
+
 }
 
 #define COM1_BASE       0x3F8
index 7d8dc3767dfe3c27fa5af500ad3c9c1bdf896fd5..b59e738a793f1cfa1fcfe0e1127bbd582981e972 100644 (file)
        for(;;);                                                        \
 } while(0)
 
+#define NOT_IMPLEMENTED do {   \
+               kprintf("NOT_IMPLEMENTED at %s:%d\n", __FILE__, __LINE__); \
+               minix_panic("NOT_IMPLEMENTED", NO_NUM); \
+} while(0)
+
+#ifdef CONFIG_BOOT_VERBOSE
+#define BOOT_VERBOSE(x)        x
+#else
+#define BOOT_VERBOSE(x)
+#endif
+
 #endif /* DEBUG_H */
index b300bbf541cb550700da1a3d25a7228604705962..d639f7f793585266b74a2b6cadbe8a6a048436e4 100644 (file)
@@ -62,6 +62,10 @@ EXTERN u32_t magictest;                      /* global magic number */
 EXTERN int verboseflags;
 #endif
 
+#ifdef CONFIG_APIC
+EXTERN int config_no_apic; /* optionaly turn off apic */
+#endif
+
 /* VM */
 EXTERN int vm_running;
 EXTERN int catch_pagefaults;
index 6ddc1f18fe76b178cb1026fca11fd03090f4c7d9..4090733cb58341c16e95ef3f14e2ba0283045ee9 100644 (file)
@@ -1,6 +1,11 @@
 #ifndef KERNEL_H
 #define KERNEL_H
 
+/* APIC is turned on by default */
+#define CONFIG_APIC
+/* boot verbose */
+#define CONFIG_BOOT_VERBOSE
+
 /* This is the master header for the kernel.  It includes some other files
  * and defines the principal constants.
  */
index 5eadff0fe520a600d17e660d21ca5b34358a5ece..777e12d4dfb753c5587b7e95515e1851b6a45ab0 100644 (file)
@@ -39,9 +39,6 @@ PUBLIC void main()
   reg_t ktsb;                  /* kernel task stack base */
   struct exec e_hdr;           /* for a copy of an a.out header */
 
-   /* Architecture-dependent initialization. */
-   arch_init();
-
    /* Global value to test segment sanity. */
    magictest = MAGICTEST;
  
@@ -184,6 +181,9 @@ PUBLIC void main()
        alloc_segments(rp);
   }
 
+  /* Architecture-dependent initialization. */
+  arch_init();
+
 #if SPROFILE
   sprofiling = 0;      /* we're not profiling until instructed to */
 #endif /* SPROFILE */
@@ -270,8 +270,8 @@ timer_t *tp;
  * down MINIX. How to shutdown is in the argument: RBT_HALT (return to the
  * monitor), RBT_MONITOR (execute given code), RBT_RESET (hard reset). 
  */
-  intr_init(INTS_ORIG);
   arch_stop_local_timer();
+  intr_init(INTS_ORIG, 0);
   arch_shutdown(tp ? tmr_arg(tp)->ta_int : RBT_PANIC);
 }
 
index e01e4c3dfe38c96f1c121fc69dd4435706f43e63..cc5241aea8ef765176462af580a93809b0e217f7 100644 (file)
@@ -19,7 +19,6 @@ _PROTOTYPE( void reset_timer, (struct timer *tp)                      );
 _PROTOTYPE( void ser_dump_proc, (void)                                 );
 
 /* main.c */
-_PROTOTYPE( void main, (void)                                          );
 _PROTOTYPE( void prepare_shutdown, (int how)                           );
 _PROTOTYPE( void minix_shutdown, (struct timer *tp)                    );
 
@@ -134,7 +133,7 @@ _PROTOTYPE( int vm_phys_memset, (phys_bytes source, u8_t pattern,
                 phys_bytes count)                                       );
 _PROTOTYPE( vir_bytes alloc_remote_segment, (u32_t *, segframe_t *,
         int, phys_bytes, vir_bytes, int));
-_PROTOTYPE( int intr_init, (int)                                       );
+_PROTOTYPE( int intr_init, (int, int)                                  );
 _PROTOTYPE( int intr_disabled, (void)                                  );
 _PROTOTYPE( void halt_cpu, (void)                                      );
 _PROTOTYPE( void arch_init, (void)                                     );
index 3580eea7d52d3de3cdb04fce391d532709e1b379..f022ec32b6c7f230e427fe34517b1fc2b3522e3b 100644 (file)
@@ -6,7 +6,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <archconst.h>
-#include <proto.h>
+#include "proto.h"
 
 FORWARD _PROTOTYPE( char *get_value, (_CONST char *params, _CONST char *key));
 /*===========================================================================*
@@ -76,11 +76,19 @@ U16_t parmoff, parmsize;    /* boot parameters offset and length */
   if(value && atoi(value) == 0)
        do_serial_debug=1;
 
+#ifdef CONFIG_APIC
+  value = get_value(params_buffer, "no_apic");
+  if(value)
+       config_no_apic = atoi(value);
+  else
+       config_no_apic = 0;
+#endif
+
   /* Return to assembler code to switch to protected mode (if 286), 
    * reload selectors and call main().
    */
 
-  intr_init(INTS_MINIX);
+  intr_init(INTS_MINIX, 0);
 }
 
 /*===========================================================================*
index c1e8ef3532168812cde8d41aa90a192a9c65f1f8..93a93a839d06453c416bc4e172f312186cf6134d 100644 (file)
@@ -27,6 +27,10 @@ int _cpufeature(int cpufeature)
                        return cpuid_feature_edx & CPUID1_EDX_PSE;
                case _CPUF_I386_PGE:
                        return cpuid_feature_edx & CPUID1_EDX_PGE;
+               case _CPUF_I386_APIC_ON_CHIP:
+                       return cpuid_feature_edx & CPUID1_EDX_APIC_ON_CHIP;
+               case _CPUF_I386_TSC:
+                       return cpuid_feature_edx & CPUID1_EDX_TSC;
        }
 
        return 0;