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.
This commit is contained in:
parent
6515c93ecf
commit
8a44a44cb9
24 changed files with 1457 additions and 40 deletions
|
@ -4,6 +4,8 @@
|
|||
|
||||
#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));
|
||||
|
||||
|
|
|
@ -72,5 +72,7 @@ sys/vm_i386.h
|
|||
/* CPUID flags */
|
||||
#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__ */
|
||||
|
|
|
@ -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 $@ $<
|
||||
|
||||
|
|
559
kernel/arch/i386/apic.c
Normal file
559
kernel/arch/i386/apic.c
Normal file
|
@ -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;
|
||||
}
|
105
kernel/arch/i386/apic.h
Normal file
105
kernel/arch/i386/apic.h
Normal file
|
@ -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__ */
|
447
kernel/arch/i386/apic_asm.S
Normal file
447
kernel/arch/i386/apic_asm.S
Normal file
|
@ -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 */
|
||||
|
44
kernel/arch/i386/apic_asm.h
Normal file
44
kernel/arch/i386/apic_asm.h
Normal file
|
@ -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__ */
|
|
@ -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)
|
||||
{
|
||||
#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)
|
||||
{
|
||||
#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)
|
||||
{
|
||||
#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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
7
kernel/arch/i386/glo.h
Normal file
7
kernel/arch/i386/glo.h
Normal file
|
@ -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__ */
|
|
@ -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,6 +38,7 @@ int mine;
|
|||
*/
|
||||
int i;
|
||||
|
||||
if (!intr_disabled())
|
||||
intr_disable();
|
||||
|
||||
/* The AT and newer PS/2 have two interrupt controllers, one master,
|
||||
|
@ -42,16 +46,22 @@ int mine;
|
|||
* 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 */
|
||||
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 */
|
||||
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 */
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -81,6 +81,9 @@ _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 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"
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) );
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue