Combined IA-32's and AMD64's APIC logic into a new X86 architecture tree.

This commit is contained in:
Sebastian Biemueller 2007-07-25 18:19:03 +02:00
parent e72c5df980
commit 7f434e797f
10 changed files with 32 additions and 427 deletions

View File

@ -45,7 +45,7 @@
#include INC_PLAT(nmi.h)
#include INC_GLUE(idt.h)
#if defined(CONFIG_IOAPIC)
# include INC_ARCH(apic.h)
# include INC_ARCHX(x86,apic.h)
#endif
DECLARE_CMD (cmd_reset, root, '6', "reset", "Reset system");

View File

@ -1,401 +0,0 @@
/*********************************************************************
*
* Copyright (C) 2002-2004, 2006, Karlsruhe University
*
* File path: arch/amd64/apic.h
* Description: Driver for the Local APIC in AMD64 processors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: apic.h,v 1.6 2006/10/19 22:57:34 ud3 Exp $
*
********************************************************************/
#ifndef __ARCH__AMD64__APIC_H__
#define __ARCH__AMD64__APIC_H__
#include <debug.h>
#include INC_ARCH(pagebits.h)
#include INC_GLUE(hwspace.h)
template <u64_t base> class local_apic_t {
private:
/* register numbers */
enum regno_t {
APIC_ID =0x020,
APIC_VERSION =0x030,
APIC_TASK_PRIO =0x080,
APIC_ARBITR_PRIO =0x090,
APIC_PROC_PRIO =0x0A0,
APIC_EOI =0x0B0,
APIC_LOCAL_DEST =0x0D0,
APIC_DEST_FORMAT =0x0E0,
APIC_SVR =0x0F0,
APIC_ISR_BASE =0x100,
APIC_TMR_BASE =0x180,
APIC_IRR_BASE =0x200,
APIC_ERR_STATUS =0x280,
APIC_INTR_CMD1 =0x300,
APIC_INTR_CMD2 =0x310,
APIC_LVT_TIMER =0x320,
APIC_LVT_THERMAL =0x330,
APIC_PERF_COUNTER =0x340,
APIC_LVT_LINT0 =0x350,
APIC_LVT_LINT1 =0x360,
APIC_LVT_ERROR =0x370,
APIC_TIMER_COUNT =0x380,
APIC_TIMER_CURRENT =0x390,
APIC_TIMER_DIVIDE =0x3E0
};
/* raw register access */
u32_t read_reg(regno_t reg) { return *((volatile u32_t*)(base + reg)); };
void write_reg(regno_t reg, u32_t val) { *((volatile u32_t*)(base + reg)) = val; };
class lint_vector_t
{
public:
union {
u32_t raw;
struct {
BITFIELD8(
u32_t,
vector : 8,
delivery_mode : 3,
delivery_status : 1,
polarity : 1,
remote_irr : 1,
trigger_mode : 1,
masked : 1,
reserved : 16);
} x;
};
};
class command_reg_t
{
public:
union {
u32_t raw;
struct {
u32_t vector : 8;
u32_t delivery_mode : 3;
u32_t destination_mode : 1;
u32_t delivery_status : 1;
u32_t reserved_0 : 1;
u32_t level : 1;
u32_t trigger_mode : 1;
u32_t reserved_1 : 2;
u32_t destination : 2;
u32_t reserved_2 : 12;
} x;
};
};
class dest_format_reg_t
{
public:
union {
u32_t raw;
struct {
BITFIELD2(
u32_t,
reserved : 28,
model : 4);
} x;
};
};
class prio_reg_t
{
public:
union {
u32_t raw;
struct {
BITFIELD3(
u32_t,
subprio : 4,
prio : 4,
reserved : 24);
} x;
};
};
class version_reg_t
{
public:
union {
u32_t raw;
struct {
BITFIELD4 (
u32_t,
version : 8,
reserved_0 : 8,
max_lvt : 8,
reserved_1 : 8);
} x;
};
};
class spurious_int_vector_reg_t
{
public:
union {
u32_t raw;
struct {
BITFIELD4(
u32_t,
vector : 8,
enabled : 1,
focus_processor : 1,
reserved : 22);
} x;
};
};
void set_prio(regno_t reg, u8_t prio, u8_t subprio)
{
prio_reg_t preg;
preg.raw = read_reg(reg);
preg.x.prio = prio;
preg.x.subprio = subprio;
write_reg(reg, preg.raw);
}
public:
u8_t id() { return (read_reg(APIC_ID) >> 24); }
void set_id(u8_t id) {
write_reg(APIC_ID, (read_reg(APIC_ID) & 0x00ffffff) | (u32_t)id << 24);
}
u8_t version() {
version_reg_t vreg;
vreg.raw = read_reg(APIC_VERSION);
return vreg.x.version;
}
bool enable(u8_t spurious_int_vector);
bool disable();
void set_task_prio(u8_t prio, u8_t subprio = 0)
{ set_prio (APIC_TASK_PRIO, prio, subprio); }
/* interrupt vectors */
enum lvt_t
{
lvt_timer = 0,
lvt_thermal_monitor = 1,
lvt_perfcount = 2,
lvt_lint0 = 3,
lvt_lint1 = 4,
lvt_error = 5
};
enum delivery_mode_t
{
fixed = 0,
smi = 2,
nmi = 4,
init = 5,
startup = 6,
extint = 7
};
enum pin_polarity_t
{
active_high = 0,
active_low = 1
};
enum trigger_mode_t
{
edge = 0,
level = 1
};
bool set_vector(lvt_t lvt, delivery_mode_t del_mode,
pin_polarity_t polarity,
trigger_mode_t trigger_mode);
public:
/* Timer handling */
u32_t timer_get() {
return read_reg(APIC_TIMER_CURRENT);
}
void timer_set(u32_t count) {
write_reg(APIC_TIMER_COUNT, count);
}
void timer_setup(u8_t irq, bool periodic) {
write_reg(APIC_LVT_TIMER,
(((periodic ? 1 : 0) << 17)) | irq);
}
void timer_set_divisor(u32_t divisor) {
divisor &= 0x7;
u32_t val = read_reg(APIC_TIMER_DIVIDE);
val &= ~0xf;
if (divisor == 1)
val = val | 0xb;
else
{
divisor--;
val = val | ((divisor << 1) & 0x8) | (divisor & 0x3);
}
write_reg(APIC_TIMER_DIVIDE, val);
}
public:
/* IRQ handling */
void EOI() { write_reg(APIC_EOI, 0); }
void mask(lvt_t lvt)
{
lint_vector_t vec;
vec.raw = read_reg((regno_t)(APIC_LVT_TIMER + (lvt * 0x10)));
vec.x.masked = 1;
write_reg((regno_t)(APIC_LVT_TIMER + (lvt * 0x10)), vec.raw);
}
void unmask(lvt_t lvt)
{
lint_vector_t vec;
vec.raw = read_reg(APIC_LVT_TIMER + (lvt * 0x10));
vec.x.masked = 0;
write_reg(APIC_LVT_TIMER + (lvt * 0x10));
}
bool get_trigger_mode(u8_t irq)
{
word_t tmr = read_reg((regno_t)(APIC_TMR_BASE + ((irq & ~0x1f) >> 1)));
return tmr & (1 << (irq & 0x1f));
}
public:
/* SMP handling */
void send_startup_ipi(u8_t apic_id, void(*startup_func)(void));
void send_init_ipi(u8_t apic_id, bool assert);
void send_ipi(u8_t apic_id, u8_t vector);
void broadcast_ipi(u8_t vector, bool self = false);
};
template <u64_t base>
INLINE bool local_apic_t<base>::enable(u8_t spurious_int_vector)
{
/* check that this is really an APIC */
if ((version() & 0xf0) != 0x10){
printf("version = %x \n", version());
return false;
}
/* Opteron support arbitrary SIV - check! */
if ((spurious_int_vector & 0xf) != 0xf)
{
if (version() != 0x14)
return false;
}
/* enable and set spurious interrupt vector */
spurious_int_vector_reg_t svr;
svr.raw = read_reg(APIC_SVR);
svr.x.enabled = 1;
svr.x.focus_processor = 0;
svr.x.vector = spurious_int_vector;
write_reg(APIC_SVR, svr.raw);
/* set to flat model -- other models dropped with P4 anyway */
dest_format_reg_t dest;
dest.raw = read_reg(APIC_DEST_FORMAT);
dest.x.model = 0xf; // flat model
write_reg(APIC_DEST_FORMAT, dest.raw);
return true;
}
template <u64_t base>
INLINE bool local_apic_t<base>::disable()
{
spurious_int_vector_reg_t svr;
svr.raw = read_reg(APIC_SVR);
svr.x.enabled = 0;
write_reg(APIC_SVR, svr.raw);
return true;
}
template <u64_t base>
INLINE void local_apic_t<base>::send_startup_ipi(u8_t apic_id, void(*startup_func)(void))
{
//ASSERT(((word_t)startup & ~IA32_PAGE_MASK) == 0);
//ASSERT(((word_t)startup >> (IA32_PAGE_BITS + 8)) == 0);
// destination
write_reg(APIC_INTR_CMD2, ((word_t)apic_id) << (56 - 32));
command_reg_t reg;
reg.raw = read_reg(APIC_INTR_CMD1);
// the startup-address of the receiving processor is
// 0x000VV000, where VV is sent with the SIPI.
reg.x.vector = (((u64_t)startup_func) >> 12) & 0xff;
reg.x.delivery_mode = startup;
reg.x.destination_mode = 0;
reg.x.destination = 0;
reg.x.level = 0;
reg.x.trigger_mode = 0;
write_reg(APIC_INTR_CMD1, reg.raw);
}
template <u64_t base>
INLINE void local_apic_t<base>::send_init_ipi(u8_t apic_id, bool assert)
{
// destination
write_reg(APIC_INTR_CMD2, ((word_t)apic_id) << (56 - 32));
command_reg_t reg;
reg.raw = read_reg(APIC_INTR_CMD1);
reg.x.vector = 0;
reg.x.delivery_mode = init;
reg.x.destination_mode = 0;
reg.x.destination = 0;
reg.x.level = assert ? 1 : 0;
reg.x.trigger_mode = 1;
write_reg(APIC_INTR_CMD1, reg.raw);
}
template <u64_t base>
INLINE void local_apic_t<base>::send_ipi(u8_t apic_id, u8_t vector)
{
// destination
write_reg(APIC_INTR_CMD2, ((word_t)apic_id) << (56 - 32));
command_reg_t reg;
reg.raw = 0;
reg.x.vector = vector;
write_reg(APIC_INTR_CMD1, reg.raw);
}
template <u64_t base>
INLINE void local_apic_t<base>::broadcast_ipi(u8_t vector, bool self)
{
command_reg_t reg;
reg.raw = 0;
reg.x.destination = 2 | (self ? 0 : 1);
reg.x.vector = vector;
write_reg(APIC_INTR_CMD1, reg.raw);
}
#endif /* !__ARCH__AMD64__APIC_H__ */

View File

@ -2,8 +2,8 @@
*
* Copyright (C) 2002-2004, Karlsruhe University
*
* File path: arch/ia32/apic.h
* Description: Driver for the Local APIC in IA-32 processors
* File path: arch/x86/apic.h
* Description: Driver for the Local APIC in x86 processors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -26,14 +26,15 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: apic.h,v 1.9 2006/06/16 10:25:06 stoess Exp $
* $Id: apic.h,v 1.4.4.4 2006/12/05 15:53:04 skoglund Exp $
*
********************************************************************/
#ifndef __ARCH__IA32__APIC_H__
#define __ARCH__IA32__APIC_H__
#ifndef __ARCH__X86__APIC_H__
#define __ARCH__X86__APIC_H__
template <u32_t base> class local_apic_t {
template <word_t base> class local_apic_t
{
private:
/* register numbers */
@ -300,14 +301,14 @@ public:
};
template <u32_t base>
template <word_t base>
INLINE bool local_apic_t<base>::enable(u8_t spurious_int_vector)
{
/* check that this is really an APIC */
if ((version() & 0xf0) != 0x10)
return false;
/* only P4 and Xeon support arbitrary SIV - check! */
/* only P4, Xeon, and Opteron support arbitrary SIV - check! */
if ((spurious_int_vector & 0xf) != 0xf)
{
if (version() != 0x14)
@ -331,7 +332,7 @@ INLINE bool local_apic_t<base>::enable(u8_t spurious_int_vector)
return true;
}
template <u32_t base>
template <word_t base>
INLINE bool local_apic_t<base>::disable()
{
spurious_int_vector_reg_t svr;
@ -342,7 +343,7 @@ INLINE bool local_apic_t<base>::disable()
return enabled;
}
template <u32_t base>
template <word_t base>
INLINE void local_apic_t<base>::send_startup_ipi(u8_t apic_id, void(*startup_func)(void))
{
//ASSERT(((word_t)startup & ~IA32_PAGE_MASK) == 0);
@ -352,7 +353,9 @@ INLINE void local_apic_t<base>::send_startup_ipi(u8_t apic_id, void(*startup_fun
write_reg(APIC_INTR_CMD2, ((word_t)apic_id) << (56 - 32));
command_reg_t reg;
reg.raw = read_reg(APIC_INTR_CMD1);
reg.x.vector = ((u32_t)startup_func) >> IA32_PAGE_BITS;
// the startup-address of the receiving processor is
// 0x000VV000, where VV is sent with the SIPI.
reg.x.vector = ((u32_t)startup_func) >> 12 & 0xff;
reg.x.delivery_mode = startup;
reg.x.destination_mode = 0;
reg.x.destination = 0;
@ -361,7 +364,7 @@ INLINE void local_apic_t<base>::send_startup_ipi(u8_t apic_id, void(*startup_fun
write_reg(APIC_INTR_CMD1, reg.raw);
}
template <u32_t base>
template <word_t base>
INLINE void local_apic_t<base>::send_init_ipi(u8_t apic_id, bool assert)
{
// destination
@ -377,7 +380,7 @@ INLINE void local_apic_t<base>::send_init_ipi(u8_t apic_id, bool assert)
write_reg(APIC_INTR_CMD1, reg.raw);
}
template <u32_t base>
template <word_t base>
INLINE void local_apic_t<base>::send_nmi(u8_t apic_id)
{
// destination
@ -394,7 +397,7 @@ INLINE void local_apic_t<base>::send_nmi(u8_t apic_id)
}
template <u32_t base>
template <word_t base>
INLINE void local_apic_t<base>::send_ipi(u8_t apic_id, u8_t vector)
{
// destination
@ -405,7 +408,7 @@ INLINE void local_apic_t<base>::send_ipi(u8_t apic_id, u8_t vector)
write_reg(APIC_INTR_CMD1, reg.raw);
}
template <u32_t base>
template <word_t base>
INLINE void local_apic_t<base>::broadcast_ipi(u8_t vector, bool self)
{
command_reg_t reg;
@ -415,4 +418,4 @@ INLINE void local_apic_t<base>::broadcast_ipi(u8_t vector, bool self)
write_reg(APIC_INTR_CMD1, reg.raw);
}
#endif /* !__ARCH__IA32__APIC_H__ */
#endif /* !__ARCH__X86__APIC_H__ */

View File

@ -50,6 +50,7 @@
* #include INC_CPU(x.h) includes include/arch/ia32/p4/x.h
* #include INC_PLAT(x.h) includes include/platform/pc99/x.h
* #include INC_GLUE(x.h) includes include/glue/v4-ia32/x.h
* #include INC_ARCHX(x86,x.h) includes include/arch/x86/x.h
*
*/
#define INC_ARCH(x) <arch/__ARCH__/x>
@ -61,6 +62,9 @@
#define INC_GLUE_API_CPU(x) <glue/__API__-__ARCH__/__CPU__/x>
#define INC_GLUE_API_PLAT(x) <glue/__API__-__PLATFORM__/x>
#define INC_ARCHX(x,y) <arch/x/y>
/* use this to place code/data in a certain section */
#define SECTION(x) __attribute__((section(x)))
#define UNIT(x) __attribute__((section(".data." x)))

View File

@ -47,7 +47,7 @@
#include INC_ARCH(hwcr.h)
#include INC_ARCH(segdesc.h)
#include INC_ARCH(tss.h)
#include INC_ARCH(apic.h)
#include INC_ARCHX(x86,apic.h)
#include INC_ARCH(config.h)
#include INC_GLUE(intctrl.h)

View File

@ -7,7 +7,7 @@
#include INC_GLUE(config.h)
#include INC_GLUE(idt.h)
#include INC_ARCH(apic.h)
#include INC_ARCHX(x86,apic.h)
#include INC_ARCH(trapgate.h)
#include INC_ARCH(debug.h)

View File

@ -1,6 +1,6 @@
/*********************************************************************
*
* Copyright (C) 2002-2003, 2006, Karlsruhe University
* Copyright (C) 2002-2003, 2006-2007, Karlsruhe University
*
* File path: glue/v4-ia32/debug.cc
* Description: Debugging support
@ -37,7 +37,7 @@
#include INC_ARCH(traps.h)
#include INC_ARCH(trapgate.h)
#include INC_ARCH(apic.h)
#include INC_ARCHX(x86,apic.h)
#define KDB_STACK_SIZE KTCB_SIZE
static char kdb_stack[KDB_STACK_SIZE] UNIT("cpulocal")

View File

@ -1,6 +1,6 @@
/*********************************************************************
*
* Copyright (C) 2002-2003, Karlsruhe University
* Copyright (C) 2002-2003, 2007, Karlsruhe University
*
* File path: glue/v4-ia32/smp.cc
* Description: IA32 MP implementation
@ -34,7 +34,7 @@
#include INC_GLUE(config.h)
#include INC_GLUE(idt.h)
#include INC_API(smp.h)
#include INC_ARCH(apic.h)
#include INC_ARCHX(x86,apic.h)
#include INC_ARCH(trapgate.h)
#ifdef CONFIG_SMP_IDLE_POLL

View File

@ -36,7 +36,6 @@
#include INC_PLAT(acpi.h)
#include INC_ARCH(apic.h)
#include INC_ARCH(ioport.h)
#include INC_ARCH(trapgate.h)
#include INC_GLUE(idt.h)

View File

@ -1,6 +1,6 @@
/*********************************************************************
*
* Copyright (C) 2002-2004, 2006, Karlsruhe University
* Copyright (C) 2002-2004, 2006-2007, Karlsruhe University
*
* File path: platform/generic/intctrl-apic.h
* Description: Driver for APIC+IOAPIC
@ -37,7 +37,7 @@
#endif
#include INC_PLAT(82093.h)
#include INC_ARCH(apic.h)
#include INC_ARCHX(x86,apic.h)
#include <sync.h>
#include <linear_ptab.h>