From 8a44a44cb9ab208a193eebfcf4546d7486f1b340 Mon Sep 17 00:00:00 2001 From: Tomas Hruby Date: Mon, 16 Nov 2009 21:41:44 +0000 Subject: [PATCH] Local APIC - 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. --- include/minix/cpufeature.h | 6 +- include/sys/vm_i386.h | 6 +- kernel/arch/i386/Makefile | 9 +- kernel/arch/i386/apic.c | 559 +++++++++++++++++++++++++++ kernel/arch/i386/apic.h | 105 +++++ kernel/arch/i386/apic_asm.S | 447 +++++++++++++++++++++ kernel/arch/i386/apic_asm.h | 44 +++ kernel/arch/i386/clock.c | 43 ++- kernel/arch/i386/glo.h | 7 + kernel/arch/i386/i8259.c | 34 +- kernel/arch/i386/include/archconst.h | 16 +- kernel/arch/i386/klib386.S | 97 ++++- kernel/arch/i386/memory.c | 29 +- kernel/arch/i386/protect.c | 10 +- kernel/arch/i386/proto.h | 9 +- kernel/arch/i386/sconst.h | 3 +- kernel/arch/i386/system.c | 26 ++ kernel/debug.h | 11 + kernel/glo.h | 4 + kernel/kernel.h | 5 + kernel/main.c | 8 +- kernel/proto.h | 3 +- kernel/start.c | 12 +- lib/i386/misc/_cpufeature.c | 4 + 24 files changed, 1457 insertions(+), 40 deletions(-) create mode 100644 kernel/arch/i386/apic.c create mode 100644 kernel/arch/i386/apic.h create mode 100644 kernel/arch/i386/apic_asm.S create mode 100644 kernel/arch/i386/apic_asm.h create mode 100644 kernel/arch/i386/glo.h diff --git a/include/minix/cpufeature.h b/include/minix/cpufeature.h index 0dcb9a154..a5fec4ada 100644 --- a/include/minix/cpufeature.h +++ b/include/minix/cpufeature.h @@ -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)); diff --git a/include/sys/vm_i386.h b/include/sys/vm_i386.h index 12ea709cc..da94c341b 100644 --- a/include/sys/vm_i386.h +++ b/include/sys/vm_i386.h @@ -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__ */ diff --git a/kernel/arch/i386/Makefile b/kernel/arch/i386/Makefile index afbeea668..0779512f7 100644 --- a/kernel/arch/i386/Makefile +++ b/kernel/arch/i386/Makefile @@ -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 index 000000000..b52a73d87 --- /dev/null +++ b/kernel/arch/i386/apic.c @@ -0,0 +1,559 @@ +/* + * APIC handling routines. APIC is a requirement for SMP + */ +#include "../../kernel.h" + +#include +#include +#include +#include + +#include + +#include "../../proc.h" +#include "../..//glo.h" +#include "proto.h" + +#include + +#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 index 000000000..fa7dde5a1 --- /dev/null +++ b/kernel/arch/i386/apic.h @@ -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 + +#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 index 000000000..28c53b414 --- /dev/null +++ b/kernel/arch/i386/apic_asm.S @@ -0,0 +1,447 @@ +#include +#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 index 000000000..f15160679 --- /dev/null +++ b/kernel/arch/i386/apic_asm.h @@ -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__ */ diff --git a/kernel/arch/i386/clock.c b/kernel/arch/i386/clock.c index f5e456dc2..9cf0e7219 100644 --- a/kernel/arch/i386/clock.c +++ b/kernel/arch/i386/clock.c @@ -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; +#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); - put_irq_handler(&pic_timer_hook, CLOCK_IRQ, - (irq_handler_t)bsp_timer_int_handler); + 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 index 000000000..d056d5c20 --- /dev/null +++ b/kernel/arch/i386/glo.h @@ -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__ */ diff --git a/kernel/arch/i386/i8259.c b/kernel/arch/i386/i8259.c index 19ed4ed26..9f63b04bc 100644 --- a/kernel/arch/i386/i8259.c +++ b/kernel/arch/i386/i8259.c @@ -19,14 +19,17 @@ #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); +} + diff --git a/kernel/arch/i386/include/archconst.h b/kernel/arch/i386/include/archconst.h index 0bf7a3cbd..137d6aae9 100644 --- a/kernel/arch/i386/include/archconst.h +++ b/kernel/arch/i386/include/archconst.h @@ -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 */ @@ -100,6 +100,10 @@ #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. */ @@ -140,4 +144,14 @@ #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 */ diff --git a/kernel/arch/i386/klib386.S b/kernel/arch/i386/klib386.S index 944c590a9..bb74790bf 100644 --- a/kernel/arch/i386/klib386.S +++ b/kernel/arch/i386/klib386.S @@ -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 diff --git a/kernel/arch/i386/memory.c b/kernel/arch/i386/memory.c index c11b5c11d..312d6abc9 100644 --- a/kernel/arch/i386/memory.c +++ b/kernel/arch/i386/memory.c @@ -19,6 +19,10 @@ #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; } diff --git a/kernel/arch/i386/protect.c b/kernel/arch/i386/protect.c index 29870b96c..30f6597f2 100644 --- a/kernel/arch/i386/protect.c +++ b/kernel/arch/i386/protect.c @@ -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; diff --git a/kernel/arch/i386/proto.h b/kernel/arch/i386/proto.h index 24cc63f95..08828a337 100644 --- a/kernel/arch/i386/proto.h +++ b/kernel/arch/i386/proto.h @@ -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" diff --git a/kernel/arch/i386/sconst.h b/kernel/arch/i386/sconst.h index 2dbaa0163..09ee7d989 100644 --- a/kernel/arch/i386/sconst.h +++ b/kernel/arch/i386/sconst.h @@ -128,7 +128,6 @@ mov %esi, %ss:BPREG(%ebp) ;\ \ RESTORE_KERNEL_SEGS ;\ - SAVE_TRAP_CTX(displ, %ebp, %esi) ;\ - ; + SAVE_TRAP_CTX(displ, %ebp, %esi) ; #endif /* __SCONST_H__ */ diff --git a/kernel/arch/i386/system.c b/kernel/arch/i386/system.c index dc0a12e83..426c53dc6 100644 --- a/kernel/arch/i386/system.c +++ b/kernel/arch/i386/system.c @@ -16,6 +16,10 @@ #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 diff --git a/kernel/debug.h b/kernel/debug.h index 7d8dc3767..b59e738a7 100644 --- a/kernel/debug.h +++ b/kernel/debug.h @@ -75,4 +75,15 @@ 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 */ diff --git a/kernel/glo.h b/kernel/glo.h index b300bbf54..d639f7f79 100644 --- a/kernel/glo.h +++ b/kernel/glo.h @@ -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; diff --git a/kernel/kernel.h b/kernel/kernel.h index 6ddc1f18f..4090733cb 100644 --- a/kernel/kernel.h +++ b/kernel/kernel.h @@ -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. */ diff --git a/kernel/main.c b/kernel/main.c index 5eadff0fe..777e12d4d 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -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); } diff --git a/kernel/proto.h b/kernel/proto.h index e01e4c3df..cc5241aea 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -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) ); diff --git a/kernel/start.c b/kernel/start.c index 3580eea7d..f022ec32b 100644 --- a/kernel/start.c +++ b/kernel/start.c @@ -6,7 +6,7 @@ #include #include #include -#include +#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); } /*===========================================================================* diff --git a/lib/i386/misc/_cpufeature.c b/lib/i386/misc/_cpufeature.c index c1e8ef353..93a93a839 100644 --- a/lib/i386/misc/_cpufeature.c +++ b/lib/i386/misc/_cpufeature.c @@ -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;