support for apic global disable

separate between I/O apic and local apic
This commit is contained in:
Stanislav Shwartsman 2009-02-18 22:25:04 +00:00
parent 87b705d036
commit 1b72e66bb3
9 changed files with 173 additions and 155 deletions

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: apic.cc,v 1.118 2009-02-17 19:44:01 sshwarts Exp $
// $Id: apic.cc,v 1.119 2009-02-18 22:24:52 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002 Zwane Mwaikambo, Stanislav Shwartsman
@ -29,6 +29,8 @@
#define LOG_THIS this->
#define APIC_UNKNOWN_ID 0xff
#define APIC_BROADCAST_PHYSICAL_DESTINATION_MODE (APIC_MAX_ID)
#define BX_LAPIC_FIRST_VECTOR 0x10
@ -166,78 +168,13 @@ void apic_bus_broadcast_smi(void)
////////////////////////////////////
bx_generic_apic_c::bx_generic_apic_c(bx_phy_address base)
bx_local_apic_c::bx_local_apic_c(BX_CPU_C *mycpu)
: base_addr(BX_LAPIC_BASE_ADDR), cpu(mycpu), cpu_id(cpu->which_cpu())
{
put("APIC?");
id = APIC_UNKNOWN_ID;
set_base(base);
}
void bx_generic_apic_c::set_base(bx_phy_address newbase)
{
newbase &= (~0xfff);
base_addr = newbase;
if (id != APIC_UNKNOWN_ID)
BX_INFO(("relocate APIC id=%d to 0x" FMT_PHY_ADDRX, id, newbase));
}
void bx_generic_apic_c::set_id(Bit32u newid)
{
BX_INFO(("set APIC ID to %d", newid));
id = newid;
}
bx_bool bx_generic_apic_c::is_selected(bx_phy_address addr, unsigned len)
{
if((addr & ~0xfff) == get_base()) {
if((addr & 0xf) != 0)
BX_INFO(("warning: misaligned APIC access. addr=0x" FMT_PHY_ADDRX ", len=%d", addr, len));
return 1;
}
return 0;
}
void bx_generic_apic_c::read(bx_phy_address addr, void *data, unsigned len)
{
if((addr & ~0x3) != ((addr+len-1) & ~0x3)) {
BX_PANIC(("APIC read at address 0x" FMT_PHY_ADDRX " spans 32-bit boundary !", addr));
return;
}
Bit32u value;
read_aligned(addr & ~0x3, &value);
if(len == 4) { // must be 32-bit aligned
*((Bit32u *)data) = value;
return;
}
// handle partial read, independent of endian-ness
value >>= (addr&3)*8;
if (len == 1)
*((Bit8u *) data) = value & 0xff;
else if (len == 2)
*((Bit16u *)data) = value & 0xffff;
else
BX_PANIC(("Unsupported APIC read at address 0x" FMT_PHY_ADDRX ", len=%d", addr, len));
}
void bx_generic_apic_c::write(bx_phy_address addr, void *data, unsigned len)
{
if (len != 4) {
BX_PANIC(("APIC write with len=%d (should be 4)", len));
return;
}
if(addr & 0xf) {
BX_PANIC(("APIC write at unaligned address 0x" FMT_PHY_ADDRX, addr));
return;
}
write_aligned(addr, (Bit32u*) data);
}
bx_local_apic_c::bx_local_apic_c(BX_CPU_C *mycpu)
: bx_generic_apic_c(BX_LAPIC_BASE_ADDR), cpu(mycpu), cpu_id(cpu->which_cpu())
{
// KPL: Register a non-active timer for use when the timer is started.
// Register a non-active timer for use when the timer is started.
timer_handle = bx_pc_system.register_timer_ticks(this,
BX_CPU(0)->lapic.periodic_smf, 0, 0, 0, "lapic");
timer_active = 0;
@ -249,8 +186,6 @@ bx_local_apic_c::bx_local_apic_c(BX_CPU_C *mycpu)
void bx_local_apic_c::reset(unsigned type)
{
UNUSED(type);
/* same as INIT but also sets arbitration ID and APIC ID */
init();
}
@ -259,8 +194,6 @@ void bx_local_apic_c::init()
{
int i;
bx_generic_apic_c::init();
BX_INFO(("local apic in %s initializing",
(cpu && cpu->name) ? cpu->name : "?"));
@ -293,13 +226,24 @@ void bx_local_apic_c::init()
spurious_vector = 0xff; // software disabled(bit 8)
software_enabled = 0;
focus_disable = 0;
global_enabled = 1;
focus_disable = 0;
}
void bx_local_apic_c::set_id(Bit8u newid)
void bx_local_apic_c::set_base(bx_phy_address newbase)
{
bx_generic_apic_c::set_id(newid);
sprintf(cpu->name, "CPU apicid=%02x",(Bit32u)id);
global_enabled = (newbase >> 11) & 1;
newbase &= ~((bx_phy_address) 0xfff);
base_addr = newbase;
if (id != APIC_UNKNOWN_ID)
BX_INFO(("relocate APIC id=%d to 0x" FMT_PHY_ADDRX, id, newbase));
}
void bx_local_apic_c::set_id(Bit32u new_id)
{
id = new_id;
sprintf(cpu->name, "CPU apicid=%02x", id);
if(id < APIC_MAX_ID) {
char buffer[16];
sprintf(buffer, "APIC%x", id);
@ -307,12 +251,61 @@ void bx_local_apic_c::set_id(Bit8u newid)
sprintf(buffer, "CPU%x", id);
cpu->put(buffer);
} else {
BX_INFO(("naming convention for apics requires id=0-%d only", APIC_MAX_ID));
BX_INFO(("naming convention for APICs requires id=0-%d only", APIC_MAX_ID));
}
BX_INFO(("80%d86", BX_CPU_LEVEL));
}
bx_bool bx_local_apic_c::is_selected(bx_phy_address addr)
{
if (! global_enabled) return 0;
if((addr & ~0xfff) == base_addr) {
if((addr & 0xf) != 0)
BX_INFO(("warning: misaligned APIC access. addr=0x" FMT_PHY_ADDRX, addr));
return 1;
}
return 0;
}
void bx_local_apic_c::read(bx_phy_address addr, void *data, unsigned len)
{
if((addr & ~0x3) != ((addr+len-1) & ~0x3)) {
BX_PANIC(("APIC read at address 0x" FMT_PHY_ADDRX " spans 32-bit boundary !", addr));
return;
}
Bit32u value;
read_aligned(addr & ~0x3, &value);
if(len == 4) { // must be 32-bit aligned
*((Bit32u *)data) = value;
return;
}
// handle partial read, independent of endian-ness
value >>= (addr&3)*8;
if (len == 1)
*((Bit8u *) data) = value & 0xff;
else if (len == 2)
*((Bit16u *)data) = value & 0xffff;
else
BX_PANIC(("Unsupported APIC read at address 0x" FMT_PHY_ADDRX ", len=%d", addr, len));
}
void bx_local_apic_c::write(bx_phy_address addr, void *data, unsigned len)
{
if (len != 4) {
BX_PANIC(("APIC write with len=%d (should be 4)", len));
return;
}
if(addr & 0xf) {
BX_PANIC(("APIC write at unaligned address 0x" FMT_PHY_ADDRX, addr));
return;
}
write_aligned(addr, (Bit32u*) data);
}
// APIC write: 4 byte write to 16-byte aligned APIC address
void bx_local_apic_c::write_aligned(bx_phy_address addr, Bit32u *data)
{
@ -948,6 +941,7 @@ void bx_local_apic_c::register_state(bx_param_c *parent)
BXRS_HEX_PARAM_SIMPLE(lapic, id);
BXRS_HEX_PARAM_SIMPLE(lapic, spurious_vector);
BXRS_PARAM_BOOL(lapic, software_enabled, software_enabled);
BXRS_PARAM_BOOL(lapic, global_enabled, global_enabled);
BXRS_PARAM_BOOL(lapic, focus_disable, focus_disable);
BXRS_HEX_PARAM_SIMPLE(lapic, task_priority);
BXRS_HEX_PARAM_SIMPLE(lapic, spurious_vector);

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: apic.h,v 1.42 2009-02-17 19:44:02 sshwarts Exp $
// $Id: apic.h,v 1.43 2009-02-18 22:24:55 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002 Zwane Mwaikambo, Stanislav Shwartsman
@ -32,28 +32,6 @@
#define APIC_LEVEL_TRIGGERED 1
#define APIC_EDGE_TRIGGERED 0
class BOCHSAPI bx_generic_apic_c : public logfunctions {
protected:
bx_phy_address base_addr;
Bit32u id;
#define APIC_UNKNOWN_ID 0xff
public:
bx_generic_apic_c(bx_phy_address base);
virtual ~bx_generic_apic_c() { }
// init is called during RESET and when an INIT message is delivered
virtual void init() { }
virtual void reset(unsigned type) {}
bx_phy_address get_base(void) const { return base_addr; }
void set_base(bx_phy_address newbase);
void set_id(Bit32u newid);
Bit32u get_id() const { return id; }
bx_bool is_selected(bx_phy_address addr, unsigned len);
virtual void read_aligned(bx_phy_address address, Bit32u *data) = 0;
void read(bx_phy_address addr, void *data, unsigned len);
virtual void write_aligned(bx_phy_address address, Bit32u *data) = 0;
void write(bx_phy_address addr, void *data, unsigned len);
};
#ifdef BX_INCLUDE_LOCAL_APIC
#define BX_CPU_APIC(i) (&(BX_CPU(i)->lapic))
@ -68,10 +46,14 @@ public:
#define BX_NUM_LOCAL_APICS BX_SMP_PROCESSORS
#define BX_LAPIC_MAX_INTS 256
class BOCHSAPI bx_local_apic_c : public bx_generic_apic_c
class BOCHSAPI bx_local_apic_c : public logfunctions
{
Bit32u spurious_vector;
bx_phy_address base_addr;
Bit32u id;
bx_bool global_enabled;
bx_bool software_enabled;
Bit32u spurious_vector;
bx_bool focus_disable;
Bit32u task_priority; // Task priority (TPR)
@ -142,12 +124,18 @@ class BOCHSAPI bx_local_apic_c : public bx_generic_apic_c
public:
bx_bool INTR;
bx_local_apic_c(BX_CPU_C *cpu);
virtual ~bx_local_apic_c() { }
virtual void reset(unsigned type);
virtual void init(void);
void set_id(Bit8u newid); // redefine to set cpu->name
virtual void write_aligned(bx_phy_address addr, Bit32u *data);
virtual void read_aligned(bx_phy_address address, Bit32u *data);
~bx_local_apic_c() { }
void reset(unsigned type);
void init(void);
bx_phy_address get_base(void) const { return base_addr; }
void set_base(bx_phy_address newbase);
void set_id(Bit32u newid);
Bit32u get_id() const { return id; }
bx_bool is_selected(bx_phy_address addr);
void read(bx_phy_address addr, void *data, unsigned len);
void write(bx_phy_address addr, void *data, unsigned len);
void write_aligned(bx_phy_address addr, Bit32u *data);
void read_aligned(bx_phy_address address, Bit32u *data);
void startup_msg(Bit32u vector);
// on local APIC, trigger means raise the CPU's INTR line. For now
// I also have to raise pc_system.INTR but that should be replaced

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cpu.h,v 1.573 2009-02-17 19:44:02 sshwarts Exp $
// $Id: cpu.h,v 1.574 2009-02-18 22:24:56 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -3129,7 +3129,7 @@ public: // for now...
#endif
#if BX_SUPPORT_APIC
BX_SMF void relocate_apic(Bit64u val_64);
BX_SMF bx_bool relocate_apic(Bit64u val_64);
#endif
BX_SMF void jump_protected(bxInstruction_c *, Bit16u cs, bx_address disp) BX_CPP_AttrRegparmN(3);

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: msr.cc,v 1.14 2009-02-17 19:44:02 sshwarts Exp $
// $Id: msr.cc,v 1.15 2009-02-18 22:24:57 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2008 Stanislav Shwartsman
@ -394,8 +394,7 @@ bx_bool BX_CPP_AttrRegparmN(2) BX_CPU_C::wrmsr(Bit32u index, Bit64u val_64)
#if BX_SUPPORT_APIC
case BX_MSR_APICBASE:
relocate_apic(val_64);
break;
return relocate_apic(val_64);
#endif
#if BX_SUPPORT_VMX
@ -512,7 +511,7 @@ bx_bool BX_CPP_AttrRegparmN(2) BX_CPU_C::wrmsr(Bit32u index, Bit64u val_64)
#endif // BX_CPU_LEVEL >= 5
#if BX_SUPPORT_APIC
void BX_CPU_C::relocate_apic(Bit64u val_64)
bx_bool BX_CPU_C::relocate_apic(Bit64u val_64)
{
/* MSR_APICBASE
* 0:7 Reserved
@ -523,14 +522,22 @@ void BX_CPU_C::relocate_apic(Bit64u val_64)
* 12:35 APIC Base Address (physical)
* 36:63 Reserved
*/
#define BX_MSR_APICBASE_RESERVED_BITS 0x6ff
if (BX_CPU_THIS_PTR msr.apicbase & 0x800) {
Bit32u val32_hi = GET32H(val_64), val32_lo = GET32L(val_64);
BX_INFO(("WRMSR: wrote %08x:%08x to MSR_APICBASE", val32_hi, val32_lo));
#if BX_PHY_ADDRESS_WIDTH == 32
if (val32_hi != 0) {
BX_PANIC(("MSR_APICBASE: Only 32 bit physical address space is emulated !"));
#if BX_SUPPORT_X86_64
if (! IsValidPhyAddr(val_64)) {
BX_ERROR(("relocate_apic: invalid physical address"));
return 0;
}
#endif
if (val32_lo & BX_MSR_APICBASE_RESERVED_BITS) {
BX_ERROR(("relocate_apic: attempt to set reserved bits"));
return 0;
}
BX_CPU_THIS_PTR msr.apicbase = val_64;
BX_CPU_THIS_PTR lapic.set_base(BX_CPU_THIS_PTR msr.apicbase);
// TLB flush is required for emulation correctness
@ -539,6 +546,8 @@ void BX_CPU_C::relocate_apic(Bit64u val_64)
else {
BX_INFO(("WRMSR: MSR_APICBASE APIC global enable bit cleared !"));
}
return 1;
}
#endif

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: paging.cc,v 1.169 2009-02-17 19:20:47 sshwarts Exp $
// $Id: paging.cc,v 1.170 2009-02-18 22:24:58 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -1657,7 +1657,7 @@ void BX_CPU_C::access_write_physical(bx_phy_address paddr, unsigned len, void *d
{
bx_phy_address a20addr = A20ADDR(paddr);
if (BX_CPU_THIS_PTR lapic.is_selected(a20addr, len)) {
if (BX_CPU_THIS_PTR lapic.is_selected(a20addr)) {
BX_CPU_THIS_PTR lapic.write(a20addr, data, len);
return;
}
@ -1669,7 +1669,7 @@ void BX_CPU_C::access_read_physical(bx_phy_address paddr, unsigned len, void *da
{
bx_phy_address a20addr = A20ADDR(paddr);
if (BX_CPU_THIS_PTR lapic.is_selected(a20addr, len)) {
if (BX_CPU_THIS_PTR lapic.is_selected(a20addr)) {
BX_CPU_THIS_PTR lapic.read(a20addr, data, len);
return;
}

View File

@ -25,7 +25,6 @@ TODO (know issues in CPU model):
[!] Some of APIC functionality still not implemented, for example
- Globally disabled APIC
- LVT pins handling
- Filter interrupts according processor priority (PPR)

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: ioapic.cc,v 1.45 2009-02-08 09:05:52 vruppert Exp $
// $Id: ioapic.cc,v 1.46 2009-02-18 22:25:02 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 MandrakeSoft S.A.
@ -36,14 +36,31 @@ class bx_ioapic_c bx_ioapic;
static bx_bool ioapic_read(bx_phy_address a20addr, unsigned len, void *data, void *param)
{
bx_ioapic.read(a20addr, data, len);
if((a20addr & ~0x3) != ((a20addr+len-1) & ~0x3)) {
BX_PANIC(("I/O APIC read at address 0x" FMT_PHY_ADDRX " spans 32-bit boundary !", a20addr));
return 1;
}
Bit32u value = bx_ioapic.read_aligned(a20addr & ~0x3);
if(len == 4) { // must be 32-bit aligned
*((Bit32u *)data) = value;
return 1;
}
// handle partial read, independent of endian-ness
value >>= (a20addr&3)*8;
if (len == 1)
*((Bit8u *) data) = value & 0xff;
else if (len == 2)
*((Bit16u *)data) = value & 0xffff;
else
BX_PANIC(("Unsupported I/O APIC read at address 0x" FMT_PHY_ADDRX ", len=%d", a20addr, len));
return 1;
}
static bx_bool ioapic_write(bx_phy_address a20addr, unsigned len, void *data, void *param)
{
if (len != 4) {
BX_PANIC (("I/O apic write with len=%d (should be 4)", len));
BX_PANIC(("I/O apic write with len=%d (should be 4)", len));
return 1;
}
@ -76,22 +93,18 @@ void bx_io_redirect_entry_t::register_state(bx_param_c *parent)
BXRS_HEX_PARAM_SIMPLE(parent, hi);
}
#define BX_IOAPIC_BASE_ADDR (0xfec00000)
#define BX_IOAPIC_BASE_ADDR (0xfec00000)
#define BX_IOAPIC_DEFAULT_ID (BX_SMP_PROCESSORS)
bx_ioapic_c::bx_ioapic_c()
: bx_generic_apic_c(BX_IOAPIC_BASE_ADDR)
bx_ioapic_c::bx_ioapic_c(): base_addr(BX_IOAPIC_BASE_ADDR)
{
set_id(BX_IOAPIC_DEFAULT_ID);
put("IOAP");
}
#define BX_IOAPIC_DEFAULT_ID (BX_SMP_PROCESSORS)
void bx_ioapic_c::init(void)
{
bx_generic_apic_c::init();
BX_INFO(("initializing I/O APIC"));
base_addr = BX_IOAPIC_BASE_ADDR;
set_id(BX_IOAPIC_DEFAULT_ID);
DEV_register_memory_handlers(&bx_ioapic,
ioapic_read, ioapic_write, base_addr, base_addr + 0xfff);
reset(BX_RESET_HARDWARE);
@ -109,39 +122,43 @@ void bx_ioapic_c::reset(unsigned type)
ioregsel = 0;
}
void bx_ioapic_c::read_aligned(bx_phy_address address, Bit32u *data)
Bit32u bx_ioapic_c::read_aligned(bx_phy_address address)
{
BX_DEBUG(("IOAPIC: read aligned addr=%08x", address));
address &= 0xff;
if (address == 0x00) {
// select register
*data = ioregsel;
return;
return ioregsel;
} else {
if (address != 0x10)
BX_PANIC(("IOAPIC: read from unsupported address"));
}
Bit32u data;
// only reached when reading data register
switch (ioregsel) {
case 0x00: // APIC ID, note this is 4bits, the upper 4 are reserved
*data = ((id & APIC_ID_MASK) << 24);
return;
data = ((id & APIC_ID_MASK) << 24);
break;
case 0x01: // version
*data = BX_IOAPIC_VERSION_ID;
return;
data = BX_IOAPIC_VERSION_ID;
break;
case 0x02:
BX_INFO(("IOAPIC: arbitration ID unsupported, returned 0"));
*data = 0;
return;
data = 0;
break;
default:
int index = (ioregsel - 0x10) >> 1;
if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
bx_io_redirect_entry_t *entry = ioredtbl + index;
*data = (ioregsel&1) ? entry->get_hi_part() : entry->get_lo_part();
return;
data = (ioregsel&1) ? entry->get_hi_part() : entry->get_lo_part();
break;
}
BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
}
return data;
}
void bx_ioapic_c::write_aligned(bx_phy_address address, Bit32u *value)
@ -262,6 +279,7 @@ void bx_ioapic_c::service_ioapic()
void bx_ioapic_c::register_state(void)
{
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "ioapic", "IOAPIC State", 4);
BXRS_HEX_PARAM_SIMPLE(list, ioregsel);
BXRS_HEX_PARAM_SIMPLE(list, intin);
BXRS_HEX_PARAM_SIMPLE(list, irr);

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: ioapic.h,v 1.29 2009-02-08 09:05:52 vruppert Exp $
// $Id: ioapic.h,v 1.30 2009-02-18 22:25:04 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 MandrakeSoft S.A.
@ -73,8 +73,11 @@ public:
void register_state(bx_param_c *parent);
};
class bx_ioapic_c : public bx_generic_apic_c
class bx_ioapic_c : public logfunctions
{
bx_phy_address base_addr;
Bit32u id;
Bit32u ioregsel; // selects between various registers
Bit32u intin;
// interrupt request bitmask, not visible from the outside. Bits in the
@ -88,14 +91,22 @@ class bx_ioapic_c : public bx_generic_apic_c
public:
bx_ioapic_c();
virtual ~bx_ioapic_c() {}
virtual void init();
virtual void reset(unsigned type);
virtual void read_aligned(bx_phy_address address, Bit32u *data);
virtual void write_aligned(bx_phy_address address, Bit32u *data);
~bx_ioapic_c() {}
void init();
void reset(unsigned type);
bx_phy_address get_base(void) const { return base_addr; }
void set_id(Bit32u new_id) { id = new_id; }
Bit32u get_id() const { return id; }
Bit32u read_aligned(bx_phy_address address);
void write_aligned(bx_phy_address address, Bit32u *data);
void set_irq_level(Bit8u int_in, bx_bool level);
void receive_eoi(Bit8u vector);
void service_ioapic(void);
void register_state(void);
};

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: misc_mem.cc,v 1.124 2009-02-17 19:20:47 sshwarts Exp $
// $Id: misc_mem.cc,v 1.125 2009-02-18 22:25:04 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 MandrakeSoft S.A.
@ -75,7 +75,7 @@ void BX_MEM_C::init_memory(Bit32u memsize)
{
unsigned idx;
BX_DEBUG(("Init $Id: misc_mem.cc,v 1.124 2009-02-17 19:20:47 sshwarts Exp $"));
BX_DEBUG(("Init $Id: misc_mem.cc,v 1.125 2009-02-18 22:25:04 sshwarts Exp $"));
if (BX_MEM_THIS actual_vector != NULL) {
BX_INFO (("freeing existing memory vector"));
@ -514,8 +514,7 @@ Bit8u *BX_MEM_C::getHostMemAddr(BX_CPU_C *cpu, bx_phy_address a20Addr, unsigned
{
#if BX_SUPPORT_APIC
if (cpu != NULL) {
bx_generic_apic_c *lapic = &cpu->lapic;
if (lapic->get_base() == (a20Addr & ~0xfff))
if (cpu->lapic.is_selected(a20Addr))
return(NULL); // Vetoed! APIC address space
}
#endif