Bochs/bochs/cpu/apic.cc

1190 lines
34 KiB
C++
Raw Normal View History

/////////////////////////////////////////////////////////////////////////
2010-04-08 19:50:39 +04:00
// $Id: apic.cc,v 1.143 2010-04-08 15:50:39 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
2009-10-15 00:45:29 +04:00
// Copyright (c) 2002-2009 Zwane Mwaikambo, Stanislav Shwartsman
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#include "iodev/iodev.h"
- apply patch.ifdef-disabled-options. Comments from that patch are below: For a whole lot of configure options, I put #if...#endif around code that is specific to the option, even in files which are normally only compiled when the option is on. This allows me to create a MS Visual C++ 6.0 workspace that supports many of these options. The workspace will basically compile every file all the time, but the code for disabled options will be commented out by the #if...#endif. This may one day lead to simplification of the Makefiles and configure scripts, but for the moment I'm leaving Makefiles and configure scripts alone. Affected options: BX_SUPPORT_APIC (cpu/apic.cc) BX_SUPPORT_X86_64 (cpu/*64.cc) BX_DEBUGGER (debug/*) BX_DISASM (disasm/*) BX_WITH_nameofgui (gui/*) BX_SUPPORT_CDROM (iodev/cdrom.cc) BX_NE2K_SUPPORT (iodev/eth*.cc, iodev/ne2k.cc) BX_SUPPORT_APIC (iodev/ioapic.cc) BX_IODEBUG_SUPPORT (iodev/iodebug.cc) BX_PCI_SUPPORT (iodev/pci*.cc) BX_SUPPORT_SB16 (iodev/sb*.cc) Modified Files: cpu/apic.cc cpu/arith64.cc cpu/ctrl_xfer64.cc cpu/data_xfer64.cc cpu/fetchdecode64.cc cpu/logical64.cc cpu/mult64.cc cpu/resolve64.cc cpu/shift64.cc cpu/stack64.cc debug/Makefile.in debug/crc.cc debug/dbg_main.cc debug/lexer.l debug/linux.cc debug/parser.c debug/parser.y disasm/dis_decode.cc disasm/dis_groups.cc gui/amigaos.cc gui/beos.cc gui/carbon.cc gui/macintosh.cc gui/rfb.cc gui/sdl.cc gui/term.cc gui/win32.cc gui/wx.cc gui/wxdialog.cc gui/wxmain.cc gui/x.cc iodev/cdrom.cc iodev/eth.cc iodev/eth_arpback.cc iodev/eth_fbsd.cc iodev/eth_linux.cc iodev/eth_null.cc iodev/eth_packetmaker.cc iodev/eth_tap.cc iodev/eth_tuntap.cc iodev/eth_win32.cc iodev/ioapic.cc iodev/iodebug.cc iodev/ne2k.cc iodev/pci.cc iodev/pci2isa.cc iodev/sb16.cc iodev/soundlnx.cc iodev/soundwin.cc
2002-11-19 08:47:45 +03:00
#if BX_SUPPORT_APIC
2010-02-28 17:52:17 +03:00
extern Bit32u apic_id_mask;
extern bx_bool simulate_xapic;
2010-02-28 17:52:17 +03:00
#define LOG_THIS this->
2009-02-20 02:19:11 +03:00
#define BX_CPU_APIC(i) (&(BX_CPU(i)->lapic))
#define BX_LAPIC_FIRST_VECTOR 0x10
#define BX_LAPIC_LAST_VECTOR 0xff
///////////// APIC BUS /////////////
2010-03-27 12:56:30 +03:00
int apic_bus_deliver_interrupt(Bit8u vector, apic_dest_t dest, Bit8u delivery_mode, bx_bool logical_dest, bx_bool level, bx_bool trig_mode)
{
2006-03-02 23:17:54 +03:00
if(delivery_mode == APIC_DM_LOWPRI)
{
2009-02-21 01:00:42 +03:00
if(! logical_dest) {
// I/O subsytem initiated interrupt with lowest priority delivery
2009-02-20 02:19:11 +03:00
// which is not supported in physical destination mode
return 0;
}
else {
return apic_bus_deliver_lowest_priority(vector, dest, trig_mode, 0);
}
}
// determine destination local apics and deliver
2009-02-21 01:00:42 +03:00
if(! logical_dest) {
2009-02-20 02:19:11 +03:00
// physical destination mode
2010-02-28 17:52:17 +03:00
if((dest & apic_id_mask) == apic_id_mask) {
return apic_bus_broadcast_interrupt(vector, delivery_mode, trig_mode, apic_id_mask);
}
else {
// the destination is single agent
for (unsigned i=0;i<BX_NUM_LOCAL_APICS;i++)
{
if(BX_CPU_APIC(i)->get_id() == dest) {
BX_CPU_APIC(i)->deliver(vector, delivery_mode, trig_mode);
return 1;
}
}
return 0;
}
2008-02-03 00:46:54 +03:00
}
else {
// logical destination mode
2006-03-02 23:17:54 +03:00
if(dest == 0) return 0;
bx_bool interrupt_delivered = 0;
for (int i=0; i<BX_NUM_LOCAL_APICS; i++) {
2006-03-02 23:17:54 +03:00
if(BX_CPU_APIC(i)->match_logical_addr(dest)) {
BX_CPU_APIC(i)->deliver(vector, delivery_mode, trig_mode);
interrupt_delivered = 1;
}
}
return interrupt_delivered;
}
}
2010-03-27 12:56:30 +03:00
int apic_bus_deliver_lowest_priority(Bit8u vector, apic_dest_t dest, bx_bool trig_mode, bx_bool broadcast)
{
2007-04-04 20:55:50 +04:00
int i;
2010-02-28 17:52:17 +03:00
if (! BX_CPU_APIC(0)->is_xapic()) {
// search for if focus processor exists
for (i=0; i<BX_NUM_LOCAL_APICS; i++) {
if(BX_CPU_APIC(i)->is_focus(vector)) {
BX_CPU_APIC(i)->deliver(vector, APIC_DM_LOWPRI, trig_mode);
return 1;
}
}
}
// focus processor not found, looking for lowest priority agent
2010-02-28 17:52:17 +03:00
int lowest_priority_agent = -1, lowest_priority = 0x100, priority;
2007-04-04 20:55:50 +04:00
for (i=0; i<BX_NUM_LOCAL_APICS; i++) {
2006-03-02 23:17:54 +03:00
if(broadcast || BX_CPU_APIC(i)->match_logical_addr(dest)) {
2010-02-28 17:52:17 +03:00
if (BX_CPU_APIC(i)->is_xapic())
priority = BX_CPU_APIC(i)->get_tpr();
else
priority = BX_CPU_APIC(i)->get_apr();
2006-03-02 23:17:54 +03:00
if(priority < lowest_priority) {
lowest_priority = priority;
lowest_priority_agent = i;
}
}
}
2006-03-02 23:17:54 +03:00
if(lowest_priority_agent >= 0)
{
BX_CPU_APIC(lowest_priority_agent)->deliver(vector, APIC_DM_LOWPRI, trig_mode);
return 1;
}
return 0;
}
int apic_bus_broadcast_interrupt(Bit8u vector, Bit8u delivery_mode, bx_bool trig_mode, int exclude_cpu)
{
2006-03-02 23:17:54 +03:00
if(delivery_mode == APIC_DM_LOWPRI)
{
return apic_bus_deliver_lowest_priority(vector, 0 /* doesn't matter */, trig_mode, 1);
}
// deliver to all bus agents except 'exclude_cpu'
for (int i=0; i<BX_NUM_LOCAL_APICS; i++) {
2006-03-02 23:17:54 +03:00
if(i == exclude_cpu) continue;
BX_CPU_APIC(i)->deliver(vector, delivery_mode, trig_mode);
}
return 1;
}
static void apic_bus_broadcast_eoi(Bit8u vector)
{
DEV_ioapic_receive_eoi(vector);
}
#endif
// available even if APIC is not compiled in
void apic_bus_deliver_smi(void)
{
BX_CPU(0)->deliver_SMI();
}
void apic_bus_broadcast_smi(void)
{
for (unsigned i=0; i<BX_SMP_PROCESSORS; i++)
BX_CPU(i)->deliver_SMI();
}
#if BX_SUPPORT_APIC
////////////////////////////////////
bx_local_apic_c::bx_local_apic_c(BX_CPU_C *mycpu, unsigned id)
2009-02-20 02:19:11 +03:00
: base_addr(BX_LAPIC_BASE_ADDR), cpu(mycpu)
{
apic_id = id;
2010-03-01 20:35:49 +03:00
#if BX_SUPPORT_SMP
2010-02-28 17:52:17 +03:00
if (apic_id >= bx_cpu_count)
BX_PANIC(("PANIC: invalid APIC_ID assigned %d (max = %d)", apic_id, bx_cpu_count));
#else
if (apic_id != 0)
BX_PANIC(("PANIC: invalid APIC_ID assigned %d", apic_id));
#endif
char buffer[16];
sprintf(buffer, "APIC%x", apic_id);
put(buffer);
// 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;
xapic = simulate_xapic; // xAPIC or legacy APIC
2010-04-03 09:59:07 +04:00
2008-06-18 01:21:17 +04:00
reset(BX_RESET_HARDWARE);
}
2008-06-18 01:21:17 +04:00
void bx_local_apic_c::reset(unsigned type)
{
2005-04-26 22:30:30 +04:00
int i;
// default address for a local APIC, can be moved
base_addr = BX_LAPIC_BASE_ADDR;
2005-12-11 23:01:54 +03:00
error_status = shadow_error_status = 0;
2009-02-20 02:19:11 +03:00
ldr = 0;
dest_format = 0xf;
icr_hi = 0;
icr_lo = 0;
task_priority = 0;
2005-04-26 22:30:30 +04:00
for(i=0; i<BX_LAPIC_MAX_INTS; i++) {
2005-04-26 22:30:30 +04:00
irr[i] = isr[i] = tmr[i] = 0;
}
timer_divconf = 0;
timer_divide_factor = 1;
timer_initial = 0;
timer_current = 0;
2006-03-02 23:09:21 +03:00
if(timer_active) {
bx_pc_system.deactivate_timer(timer_handle);
timer_active = 0;
}
2005-04-26 22:30:30 +04:00
2006-03-02 23:09:21 +03:00
for(i=0; i<APIC_LVT_ENTRIES; i++) {
lvt[i] = 0x10000; // all LVT are masked
2005-04-26 22:30:30 +04:00
}
2009-02-21 01:00:42 +03:00
// split spurious vector register to 3 fields
spurious_vector = 0xff;
software_enabled = 0;
focus_disable = 0;
2009-02-21 01:00:42 +03:00
2009-02-20 02:19:11 +03:00
mode = BX_APIC_XAPIC_MODE;
2009-02-20 20:35:55 +03:00
INTR = 0;
2010-02-28 17:52:17 +03:00
if (xapic)
apic_version_id = 0x00050014; // P4 has 6 LVT entries
else
2010-04-05 13:36:17 +04:00
apic_version_id = 0x00030010; // P6 has 4 LVT entries
}
void bx_local_apic_c::set_base(bx_phy_address newbase)
{
2010-04-08 19:50:39 +04:00
#if BX_SUPPORT_X2APIC
if (mode == BX_APIC_X2APIC_MODE)
ldr = ((apic_id & 0xfffffff0) << 16) | (1 << (apic_id & 0xf));
#endif
2009-02-20 02:19:11 +03:00
mode = (newbase >> 10) & 3;
newbase &= ~((bx_phy_address) 0xfff);
base_addr = newbase;
BX_INFO(("allocate APIC id=%d (MMIO %s) to 0x" FMT_PHY_ADDRX,
apic_id, (mode == BX_APIC_XAPIC_MODE) ? "enabled" : "disabled", newbase));
}
bx_bool bx_local_apic_c::is_selected(bx_phy_address addr)
{
2009-02-20 02:19:11 +03:00
if (mode != BX_APIC_XAPIC_MODE) 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;
}
2009-02-20 02:19:11 +03:00
Bit32u value = read_aligned(addr & ~0x3);
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;
}
2009-02-20 02:19:11 +03:00
write_aligned(addr, *((Bit32u*) data));
}
#define BX_LAPIC_ID 0x020
#define BX_LAPIC_VERSION 0x030
#define BX_LAPIC_TPR 0x080
#define BX_LAPIC_ARBITRATION_PRIORITY 0x090
#define BX_LAPIC_PPR 0x0A0
#define BX_LAPIC_EOI 0x0B0
#define BX_LAPIC_LDR 0x0D0
#define BX_LAPIC_DESTINATION_FORMAT 0x0E0
#define BX_LAPIC_SPURIOUS_VECTOR 0x0F0
#define BX_LAPIC_ISR1 0x100
#define BX_LAPIC_ISR2 0x110
#define BX_LAPIC_ISR3 0x120
#define BX_LAPIC_ISR4 0x130
#define BX_LAPIC_ISR5 0x140
#define BX_LAPIC_ISR6 0x150
#define BX_LAPIC_ISR7 0x160
#define BX_LAPIC_ISR8 0x170
#define BX_LAPIC_TMR1 0x180
#define BX_LAPIC_TMR2 0x190
#define BX_LAPIC_TMR3 0x1A0
#define BX_LAPIC_TMR4 0x1B0
#define BX_LAPIC_TMR5 0x1C0
#define BX_LAPIC_TMR6 0x1D0
#define BX_LAPIC_TMR7 0x1E0
#define BX_LAPIC_TMR8 0x1F0
#define BX_LAPIC_IRR1 0x200
#define BX_LAPIC_IRR2 0x210
#define BX_LAPIC_IRR3 0x220
#define BX_LAPIC_IRR4 0x230
#define BX_LAPIC_IRR5 0x240
#define BX_LAPIC_IRR6 0x250
#define BX_LAPIC_IRR7 0x260
#define BX_LAPIC_IRR8 0x270
#define BX_LAPIC_ESR 0x280
#define BX_LAPIC_LVT_CMCI 0x2F0
#define BX_LAPIC_ICR_LO 0x300
#define BX_LAPIC_ICR_HI 0x310
#define BX_LAPIC_LVT_TIMER 0x320
#define BX_LAPIC_LVT_THERMAL 0x330
#define BX_LAPIC_LVT_PERFMON 0x340
#define BX_LAPIC_LVT_LINT0 0x350
#define BX_LAPIC_LVT_LINT1 0x360
#define BX_LAPIC_LVT_ERROR 0x370
#define BX_LAPIC_TIMER_INITIAL_COUNT 0x380
#define BX_LAPIC_TIMER_CURRENT_COUNT 0x390
#define BX_LAPIC_TIMER_DIVIDE_CFG 0x3E0
#define BX_LAPIC_SELF_IPI 0x3F0
// APIC write: 4 byte write to 16-byte aligned APIC address
2009-02-20 02:19:11 +03:00
void bx_local_apic_c::write_aligned(bx_phy_address addr, Bit32u value)
{
BX_ASSERT((addr & 0xf) == 0);
2009-02-20 02:19:11 +03:00
unsigned apic_reg = addr & 0xff0;
2009-02-20 20:05:03 +03:00
BX_DEBUG(("LAPIC write 0x%08x to register 0x%04x", value, apic_reg));
switch(apic_reg) {
2009-02-20 02:19:11 +03:00
case BX_LAPIC_TPR: // task priority
2005-11-29 01:42:29 +03:00
set_tpr(value & 0xff);
break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_EOI: // EOI
receive_EOI(value);
break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_LDR: // logical destination
2010-02-28 17:52:17 +03:00
ldr = (value >> 24) & apic_id_mask;
2009-02-20 02:19:11 +03:00
BX_DEBUG(("set logical destination to %08x", ldr));
break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_DESTINATION_FORMAT:
2006-03-02 23:17:54 +03:00
dest_format = (value >> 28) & 0xf;
2006-03-02 23:09:21 +03:00
BX_DEBUG(("set destination format to %02x", dest_format));
break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_SPURIOUS_VECTOR:
write_spurious_interrupt_register(value);
break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_ESR: // error status reg
// Here's what the IA-devguide-3 says on p.7-45:
// The ESR is a read/write register and is reset after being written to
// by the processor. A write to the ESR must be done just prior to
// reading the ESR to allow the register to be updated.
2005-12-11 23:01:54 +03:00
error_status = shadow_error_status;
shadow_error_status = 0;
break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_ICR_LO: // interrupt command reg 0-31
2006-03-02 23:09:21 +03:00
icr_lo = value & ~(1<<12); // force delivery status bit = 0(idle)
2010-03-26 14:17:02 +03:00
send_ipi((icr_hi >> 24) & 0xff, icr_lo);
break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_ICR_HI: // interrupt command reg 31-63
icr_hi = value & 0xff000000;
break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_LVT_TIMER: // LVT Timer Reg
case BX_LAPIC_LVT_THERMAL: // LVT Thermal Monitor
case BX_LAPIC_LVT_PERFMON: // LVT Performance Counter
case BX_LAPIC_LVT_LINT0: // LVT LINT0 Reg
case BX_LAPIC_LVT_LINT1: // LVT LINT1 Reg
case BX_LAPIC_LVT_ERROR: // LVT Error Reg
{
static Bit32u lvt_mask[] = {
0x000310ff, /* TIMER */
0x000117ff, /* THERMAL */
0x000117ff, /* PERFMON */
0x0001f7ff, /* LINT0 */
0x0001f7ff, /* LINT1 */
0x000110ff /* ERROR */
};
unsigned lvt_entry = (apic_reg - BX_LAPIC_LVT_TIMER) >> 4;
lvt[lvt_entry] = value & lvt_mask[lvt_entry];
if(! software_enabled) lvt[lvt_entry] |= 0x10000;
break;
}
case BX_LAPIC_TIMER_INITIAL_COUNT:
set_initial_timer_count(value);
break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_TIMER_DIVIDE_CFG:
// only bits 3, 1, and 0 are writable
timer_divconf = value & 0xb;
2006-03-02 23:09:21 +03:00
set_divide_configuration(timer_divconf);
break;
/* all read-only registers go here */
2009-02-20 02:19:11 +03:00
case BX_LAPIC_ID: // local APIC id
case BX_LAPIC_VERSION: // local APIC version
case BX_LAPIC_ARBITRATION_PRIORITY:
case BX_LAPIC_PPR: // processor priority
// ISRs not writable
2009-02-20 02:19:11 +03:00
case BX_LAPIC_ISR1: case BX_LAPIC_ISR2:
case BX_LAPIC_ISR3: case BX_LAPIC_ISR4:
case BX_LAPIC_ISR5: case BX_LAPIC_ISR6:
case BX_LAPIC_ISR7: case BX_LAPIC_ISR8:
// TMRs not writable
2009-02-20 02:19:11 +03:00
case BX_LAPIC_TMR1: case BX_LAPIC_TMR2:
case BX_LAPIC_TMR3: case BX_LAPIC_TMR4:
case BX_LAPIC_TMR5: case BX_LAPIC_TMR6:
case BX_LAPIC_TMR7: case BX_LAPIC_TMR8:
// IRRs not writable
2009-02-20 02:19:11 +03:00
case BX_LAPIC_IRR1: case BX_LAPIC_IRR2:
case BX_LAPIC_IRR3: case BX_LAPIC_IRR4:
case BX_LAPIC_IRR5: case BX_LAPIC_IRR6:
case BX_LAPIC_IRR7: case BX_LAPIC_IRR8:
// current count for timer
case BX_LAPIC_TIMER_CURRENT_COUNT:
// all read-only registers should fall into this line
BX_INFO(("warning: write to read-only APIC register 0x%x", apic_reg));
break;
default:
2005-12-11 23:01:54 +03:00
shadow_error_status |= APIC_ERR_ILLEGAL_ADDR;
// but for now I want to know about it in case I missed some.
BX_PANIC(("APIC register %x not implemented", apic_reg));
}
}
2010-03-27 12:56:30 +03:00
void bx_local_apic_c::send_ipi(apic_dest_t dest, Bit32u lo_cmd)
{
2010-03-26 14:17:02 +03:00
int dest_shorthand = (lo_cmd >> 18) & 3;
int trig_mode = (lo_cmd >> 15) & 1;
int level = (lo_cmd >> 14) & 1;
int logical_dest = (lo_cmd >> 11) & 1;
int delivery_mode = (lo_cmd >> 8) & 7;
int vector = (lo_cmd & 0xff);
int accepted = 0;
2006-03-02 23:09:21 +03:00
if(delivery_mode == APIC_DM_INIT)
{
2006-03-02 23:09:21 +03:00
if(level == 0 && trig_mode == 1) {
// special mode in local apic. See "INIT Level Deassert" in the
// Intel Soft. Devel. Guide Vol 3, page 7-34. This magic code
2006-03-02 23:09:21 +03:00
// causes all APICs(regardless of dest address) to set their
// arbitration ID to their APIC ID. Not supported by Pentium 4
// and Intel Xeon processors.
return; // we not model APIC bus arbitration ID anyway
}
}
2006-03-02 23:09:21 +03:00
switch(dest_shorthand) {
case 0: // no shorthand, use real destination value
2009-02-20 02:19:11 +03:00
accepted = apic_bus_deliver_interrupt(vector, dest, delivery_mode, logical_dest, level, trig_mode);
break;
case 1: // self
trigger_irq(vector, trig_mode);
accepted = 1;
break;
case 2: // all including self
2010-02-28 17:52:17 +03:00
accepted = apic_bus_broadcast_interrupt(vector, delivery_mode, trig_mode, apic_id_mask);
break;
case 3: // all but self
accepted = apic_bus_broadcast_interrupt(vector, delivery_mode, trig_mode, get_id());
break;
default:
BX_PANIC(("Invalid desination shorthand %#x\n", dest_shorthand));
}
2006-03-02 23:09:21 +03:00
if(! accepted) {
BX_DEBUG(("An IPI wasn't accepted, raise APIC_ERR_TX_ACCEPT_ERR"));
shadow_error_status |= APIC_ERR_TX_ACCEPT_ERR;
}
}
void bx_local_apic_c::write_spurious_interrupt_register(Bit32u value)
{
BX_DEBUG(("write of %08x to spurious interrupt register", value));
2010-02-28 17:52:17 +03:00
if (xapic)
spurious_vector = value & 0xff;
else
// bits 0-3 of the spurious vector hardwired to '1
spurious_vector = (value & 0xf0) | 0xf;
2006-03-02 23:17:54 +03:00
software_enabled = (value >> 8) & 1;
focus_disable = (value >> 9) & 1;
2006-03-02 23:09:21 +03:00
if(! software_enabled) {
for(unsigned i=0; i<APIC_LVT_ENTRIES; i++) {
lvt[i] |= 0x10000; // all LVT are masked
}
}
}
void bx_local_apic_c::receive_EOI(Bit32u value)
{
2009-02-20 20:05:03 +03:00
BX_DEBUG(("Wrote 0x%x to EOI", value));
2006-03-02 23:09:21 +03:00
int vec = highest_priority_int(isr);
if(vec < 0) {
BX_DEBUG(("EOI written without any bit in ISR"));
} else {
2009-01-28 00:13:38 +03:00
if ((Bit32u) vec != spurious_vector) {
2009-02-20 20:05:03 +03:00
BX_DEBUG(("local apic received EOI, hopefully for vector 0x%02x", vec));
2009-01-28 00:13:38 +03:00
isr[vec] = 0;
if(tmr[vec]) {
apic_bus_broadcast_eoi(vec);
tmr[vec] = 0;
}
service_local_apic();
}
}
2009-01-28 00:13:38 +03:00
if(bx_dbg.apic) print_status();
}
2009-02-20 02:19:11 +03:00
void bx_local_apic_c::startup_msg(Bit8u vector)
{
2009-01-28 00:13:38 +03:00
cpu->deliver_SIPI(vector);
}
// APIC read: 4 byte read from 16-byte aligned APIC address
2009-02-20 02:19:11 +03:00
Bit32u bx_local_apic_c::read_aligned(bx_phy_address addr)
{
BX_ASSERT((addr & 0xf) == 0);
2009-02-20 02:19:11 +03:00
Bit32u data = 0; // default value for unimplemented registers
unsigned apic_reg = addr & 0xff0;
2009-02-20 20:05:03 +03:00
BX_DEBUG(("LAPIC read from register 0x%04x", apic_reg));
switch(apic_reg) {
2009-02-20 02:19:11 +03:00
case BX_LAPIC_ID: // local APIC id
2009-02-20 20:05:03 +03:00
data = apic_id << 24; break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_VERSION: // local APIC version
2010-02-28 17:52:17 +03:00
data = apic_version_id; break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_TPR: // task priority
data = task_priority & 0xff; break;
case BX_LAPIC_ARBITRATION_PRIORITY:
data = get_apr(); break;
case BX_LAPIC_PPR: // processor priority
data = get_ppr(); break;
case BX_LAPIC_EOI: // EOI
/*
* Read-modify-write operations should operate without generating
* exceptions, and are used by some operating systems to EOI.
* The results of reads should be ignored by the OS.
*/
break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_LDR: // logical destination
2010-02-28 17:52:17 +03:00
data = (ldr & apic_id_mask) << 24; break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_DESTINATION_FORMAT:
2009-02-20 23:44:20 +03:00
data = ((dest_format & 0xf) << 28) | 0x0fffffff; break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_SPURIOUS_VECTOR:
{
Bit32u reg = spurious_vector;
2006-03-02 23:09:21 +03:00
if(software_enabled) reg |= 0x100;
if(focus_disable) reg |= 0x200;
2009-02-20 02:19:11 +03:00
data = reg;
}
break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_ISR1: case BX_LAPIC_ISR2:
case BX_LAPIC_ISR3: case BX_LAPIC_ISR4:
case BX_LAPIC_ISR5: case BX_LAPIC_ISR6:
case BX_LAPIC_ISR7: case BX_LAPIC_ISR8:
{
2009-02-20 02:19:11 +03:00
unsigned index = (apic_reg - BX_LAPIC_ISR1) << 1;
Bit32u value = 0, mask = 1;
2006-03-02 23:09:21 +03:00
for(int i=0;i<32;i++) {
if(isr[index+i]) value |= mask;
2005-11-29 01:42:29 +03:00
mask <<= 1;
}
2009-02-20 02:19:11 +03:00
data = value;
}
break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_TMR1: case BX_LAPIC_TMR2:
case BX_LAPIC_TMR3: case BX_LAPIC_TMR4:
case BX_LAPIC_TMR5: case BX_LAPIC_TMR6:
case BX_LAPIC_TMR7: case BX_LAPIC_TMR8:
{
2009-02-20 02:19:11 +03:00
unsigned index = (apic_reg - BX_LAPIC_TMR1) << 1;
Bit32u value = 0, mask = 1;
2006-03-02 23:09:21 +03:00
for(int i=0;i<32;i++) {
if(tmr[index+i]) value |= mask;
2005-11-29 01:42:29 +03:00
mask <<= 1;
}
2009-02-20 02:19:11 +03:00
data = value;
}
break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_IRR1: case BX_LAPIC_IRR2:
case BX_LAPIC_IRR3: case BX_LAPIC_IRR4:
case BX_LAPIC_IRR5: case BX_LAPIC_IRR6:
case BX_LAPIC_IRR7: case BX_LAPIC_IRR8:
{
2009-02-20 02:19:11 +03:00
unsigned index = (apic_reg - BX_LAPIC_IRR1) << 1;
Bit32u value = 0, mask = 1;
2006-03-02 23:09:21 +03:00
for(int i=0;i<32;i++) {
if(irr[index+i]) value |= mask;
2005-11-29 01:42:29 +03:00
mask <<= 1;
}
2009-02-20 02:19:11 +03:00
data = value;
}
break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_ESR: // error status reg
data = error_status; break;
case BX_LAPIC_ICR_LO: // interrupt command reg 0-31
data = icr_lo; break;
case BX_LAPIC_ICR_HI: // interrupt command reg 31-63
data = icr_hi; break;
case BX_LAPIC_LVT_TIMER: // LVT Timer Reg
case BX_LAPIC_LVT_THERMAL: // LVT Thermal Monitor
case BX_LAPIC_LVT_PERFMON: // LVT Performance Counter
case BX_LAPIC_LVT_LINT0: // LVT LINT0 Reg
case BX_LAPIC_LVT_LINT1: // LVT Lint1 Reg
case BX_LAPIC_LVT_ERROR: // LVT Error Reg
{
2009-02-20 02:19:11 +03:00
int index = (apic_reg - BX_LAPIC_LVT_TIMER) >> 4;
data = lvt[index];
break;
}
2009-02-20 02:19:11 +03:00
case BX_LAPIC_TIMER_INITIAL_COUNT: // initial count for timer
data = timer_initial;
break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_TIMER_CURRENT_COUNT: // current count for timer
2006-03-02 23:09:21 +03:00
if(timer_active==0) {
2009-02-20 02:19:11 +03:00
data = timer_current;
2005-04-26 22:30:30 +04:00
} else {
Bit64u delta64 = (bx_pc_system.time_ticks() - ticksInitial) / timer_divide_factor;
Bit32u delta32 = (Bit32u) delta64;
2006-03-02 23:09:21 +03:00
if(delta32 > timer_initial)
BX_PANIC(("APIC: R(curr timer count): delta < initial"));
timer_current = timer_initial - delta32;
2009-02-20 02:19:11 +03:00
data = timer_current;
}
break;
2009-02-20 02:19:11 +03:00
case BX_LAPIC_TIMER_DIVIDE_CFG: // timer divide configuration
data = timer_divconf;
2005-04-26 22:30:30 +04:00
break;
default:
BX_INFO(("APIC register %08x not implemented", apic_reg));
}
2009-02-20 20:05:03 +03:00
BX_DEBUG(("read from APIC address 0x" FMT_PHY_ADDRX " = %08x", addr, data));
2009-02-20 02:19:11 +03:00
return data;
}
2006-03-02 23:09:21 +03:00
int bx_local_apic_c::highest_priority_int(Bit8u *array)
{
for(int i=BX_LAPIC_LAST_VECTOR; i>=BX_LAPIC_FIRST_VECTOR; i--)
2006-03-02 23:09:21 +03:00
if(array[i]) return i;
return -1;
}
void bx_local_apic_c::service_local_apic(void)
{
2006-03-02 23:09:21 +03:00
if(bx_dbg.apic) {
BX_INFO(("service_local_apic()"));
print_status();
}
2006-03-02 23:09:21 +03:00
if(INTR) return; // INTR already up; do nothing
// find first interrupt in irr.
int first_irr = highest_priority_int(irr);
2006-03-02 23:17:54 +03:00
if (first_irr < 0) return; // no interrupts, leave INTR=0
int first_isr = highest_priority_int(isr);
2006-06-20 20:51:03 +04:00
if (first_isr >= 0 && first_irr <= first_isr) {
2009-02-21 01:00:42 +03:00
BX_DEBUG(("lapic(%d): not delivering int 0x%02x because int 0x%02x is in service", apic_id, first_irr, first_isr));
return;
}
2006-03-02 23:17:54 +03:00
if(((Bit32u)(first_irr) & 0xf0) <= (task_priority & 0xf0)) {
2009-02-21 01:00:42 +03:00
BX_DEBUG(("lapic(%d): not delivering int 0x%02X because task_priority is 0x%02X", apic_id, first_irr, task_priority));
return;
}
// interrupt has appeared in irr. Raise INTR. When the CPU
// acknowledges, we will run highest_priority_int again and
// return it.
BX_DEBUG(("service_local_apic(): setting INTR=1 for vector 0x%02x", first_irr));
INTR = 1;
cpu->async_event = 1;
}
2006-03-02 23:09:21 +03:00
bx_bool bx_local_apic_c::deliver(Bit8u vector, Bit8u delivery_mode, Bit8u trig_mode)
{
2006-03-02 23:09:21 +03:00
switch(delivery_mode) {
case APIC_DM_FIXED:
case APIC_DM_LOWPRI:
BX_DEBUG(("Deliver lowest priority of fixed interrupt vector %02x", vector));
trigger_irq(vector, trig_mode);
break;
case APIC_DM_SMI:
BX_INFO(("Deliver SMI"));
cpu->deliver_SMI();
return 1;
case APIC_DM_NMI:
BX_INFO(("Deliver NMI"));
cpu->deliver_NMI();
return 1;
case APIC_DM_INIT:
BX_INFO(("Deliver INIT IPI"));
cpu->deliver_INIT();
break;
case APIC_DM_SIPI:
2009-02-03 22:25:37 +03:00
BX_INFO(("Deliver Start Up IPI"));
startup_msg(vector);
break;
case APIC_DM_EXTINT:
BX_DEBUG(("Deliver EXTINT vector %02x", vector));
trigger_irq(vector, trig_mode, 1);
break;
default:
return 0;
}
return 1;
}
2009-02-20 02:19:11 +03:00
void bx_local_apic_c::trigger_irq(Bit8u vector, unsigned trigger_mode, bx_bool bypass_irr_isr)
{
2009-02-20 20:05:03 +03:00
BX_DEBUG(("trigger interrupt vector=0x%02x", vector));
2008-02-03 00:46:54 +03:00
2010-02-28 17:52:17 +03:00
if(/* vector > BX_LAPIC_LAST_VECTOR || */ vector < BX_LAPIC_FIRST_VECTOR) {
2005-12-11 23:01:54 +03:00
shadow_error_status |= APIC_ERR_RX_ILLEGAL_VEC;
2005-04-26 22:30:30 +04:00
BX_INFO(("bogus vector %#x, ignoring ...", vector));
return;
}
BX_DEBUG(("triggered vector %#02x", vector));
2006-03-02 23:09:21 +03:00
if(bypass_irr_isr) {
goto service_vector;
}
2006-03-02 23:09:21 +03:00
if(irr[vector] != 0) {
BX_DEBUG(("triggered vector %#02x not accepted", vector));
return;
}
service_vector:
irr[vector] = 1;
tmr[vector] = trigger_mode; // set for level triggered
service_local_apic();
}
2009-02-20 02:19:11 +03:00
void bx_local_apic_c::untrigger_irq(Bit8u vector, unsigned trigger_mode)
{
2009-02-20 20:05:03 +03:00
BX_DEBUG(("untrigger interrupt vector=0x%02x", vector));
// hardware says "no more". clear the bit. If the CPU hasn't yet
// acknowledged the interrupt, it will never be serviced.
2006-03-02 23:09:21 +03:00
BX_ASSERT(irr[vector] == 1);
irr[vector] = 0;
2006-03-02 23:09:21 +03:00
if(bx_dbg.apic) print_status();
}
Bit8u bx_local_apic_c::acknowledge_int(void)
{
// CPU calls this when it is ready to service one interrupt
2006-03-02 23:09:21 +03:00
if(!INTR)
2009-02-20 20:05:03 +03:00
BX_PANIC(("APIC %d acknowledged an interrupt, but INTR=0", apic_id));
2006-03-02 23:09:21 +03:00
BX_ASSERT(INTR);
int vector = highest_priority_int(irr);
2006-06-20 20:51:03 +04:00
if (vector < 0) goto spurious;
2006-03-02 23:09:21 +03:00
if((vector & 0xf0) <= get_ppr()) goto spurious;
BX_ASSERT(irr[vector] == 1);
2009-02-20 20:05:03 +03:00
BX_DEBUG(("acknowledge_int() returning vector 0x%02x", vector));
irr[vector] = 0;
isr[vector] = 1;
2006-03-02 23:09:21 +03:00
if(bx_dbg.apic) {
BX_INFO(("Status after setting isr:"));
print_status();
}
INTR = 0;
cpu->async_event = 1;
service_local_apic(); // will set INTR again if another is ready
return vector;
spurious:
INTR = 0;
cpu->async_event = 1;
return spurious_vector;
}
2006-03-02 23:09:21 +03:00
void bx_local_apic_c::print_status(void)
{
2009-02-20 20:05:03 +03:00
BX_INFO(("lapic %d: status is {:", apic_id));
for(int vec=0; vec<BX_LAPIC_MAX_INTS; vec++) {
2006-03-02 23:09:21 +03:00
if(irr[vec] || isr[vec]) {
BX_INFO(("vec 0x%x: irr=%d, isr=%d", vec,(int)irr[vec],(int)isr[vec]));
}
}
BX_INFO(("}"));
}
2010-03-27 12:56:30 +03:00
bx_bool bx_local_apic_c::match_logical_addr(apic_dest_t address)
{
bx_bool match = 0;
2010-04-08 19:50:39 +04:00
#if BX_SUPPORT_X2APIC
if (mode == BX_APIC_X2APIC_MODE) {
// only cluster model supported in x2apic mode
if (address == 0xffffffff) // // broadcast all
return 1;
if ((address & 0xffff0000) == (ldr & 0xffff0000))
match = ((address & ldr & 0x0000ffff) != 0);
return match;
}
#endif
if (dest_format == 0xf) {
// flat model
2009-02-20 02:19:11 +03:00
match = ((address & ldr) != 0);
2009-02-20 20:05:03 +03:00
BX_DEBUG(("comparing MDA %02x to my LDR %02x -> %s", address,
ldr, match ? "Match" : "Not a match"));
}
else if (dest_format == 0) {
// cluster model
if (address == 0xff) // broadcast all
return 1;
2009-02-20 02:19:11 +03:00
if ((unsigned)(address & 0xf0) == (unsigned)(ldr & 0xf0))
match = ((address & ldr & 0x0f) != 0);
}
else {
BX_PANIC(("bx_local_apic_c::match_logical_addr: unsupported dest format 0x%x", dest_format));
}
return match;
}
2006-03-02 23:09:21 +03:00
Bit8u bx_local_apic_c::get_ppr(void)
{
2006-03-02 23:09:21 +03:00
int ppr = highest_priority_int(isr);
2008-02-03 00:46:54 +03:00
if((ppr < 0) || ((task_priority & 0xF0) >= ((Bit32u) ppr & 0xF0)))
ppr = task_priority;
2008-02-03 00:46:54 +03:00
else
ppr &= 0xF0;
return ppr;
}
2009-02-20 02:19:11 +03:00
void bx_local_apic_c::set_tpr(Bit8u priority)
{
2006-03-02 23:09:21 +03:00
if(priority < task_priority) {
task_priority = priority;
service_local_apic();
} else {
task_priority = priority;
}
}
Bit8u bx_local_apic_c::get_apr(void)
{
2006-03-02 23:17:54 +03:00
Bit32u tpr = (task_priority >> 4) & 0xf;
2008-06-18 00:23:16 +04:00
int first_isr = highest_priority_int(isr);
if (first_isr < 0) first_isr = 0;
int first_irr = highest_priority_int(irr);
if (first_irr < 0) first_irr = 0;
Bit32u isrv = (first_isr >> 4) & 0xf;
Bit32u irrv = (first_irr >> 4) & 0xf;
Bit8u apr;
2006-03-02 23:17:54 +03:00
if((tpr >= irrv) && (tpr > isrv)) {
apr = task_priority & 0xff;
}
else {
2006-03-02 23:17:54 +03:00
apr = ((tpr & isrv) > irrv) ?(tpr & isrv) : irrv;
apr <<= 4;
}
BX_DEBUG(("apr = %d\n", apr));
2006-03-02 23:09:21 +03:00
return(Bit8u) apr;
}
bx_bool bx_local_apic_c::is_focus(Bit8u vector)
{
2006-03-02 23:09:21 +03:00
if(focus_disable) return 0;
return(irr[vector] || isr[vector]) ? 1 : 0;
}
void bx_local_apic_c::periodic_smf(void *this_ptr)
{
2006-03-02 23:17:54 +03:00
bx_local_apic_c *class_ptr = (bx_local_apic_c *) this_ptr;
class_ptr->periodic();
}
2005-04-26 22:30:30 +04:00
void bx_local_apic_c::periodic(void)
{
2006-03-02 23:09:21 +03:00
if(!timer_active) {
2009-02-20 20:05:03 +03:00
BX_ERROR(("bx_local_apic_c::periodic called, timer_active==0"));
return;
}
// timer reached zero since the last call to periodic.
Bit32u timervec = lvt[APIC_LVT_TIMER];
2006-03-02 23:09:21 +03:00
if(timervec & 0x20000) {
// Periodic mode.
// If timer is not masked, trigger interrupt.
2006-03-02 23:09:21 +03:00
if((timervec & 0x10000)==0) {
trigger_irq(timervec & 0xff, APIC_EDGE_TRIGGERED);
2005-04-26 22:30:30 +04:00
}
2006-06-01 15:59:23 +04:00
else {
2009-02-20 20:05:03 +03:00
BX_DEBUG(("local apic timer LVT masked"));
2006-06-01 15:59:23 +04:00
}
// Reload timer values.
timer_current = timer_initial;
ticksInitial = bx_pc_system.time_ticks(); // Take a reading.
2009-02-20 20:05:03 +03:00
BX_DEBUG(("local apic timer(periodic) triggered int, reset counter to 0x%08x", timer_current));
}
else {
// one-shot mode
timer_current = 0;
// If timer is not masked, trigger interrupt.
2006-03-02 23:09:21 +03:00
if((timervec & 0x10000)==0) {
trigger_irq(timervec & 0xff, APIC_EDGE_TRIGGERED);
2005-04-26 22:30:30 +04:00
}
2006-06-01 15:59:23 +04:00
else {
2009-02-20 20:05:03 +03:00
BX_DEBUG(("local apic timer LVT masked"));
2006-06-01 15:59:23 +04:00
}
timer_active = 0;
2009-02-20 20:05:03 +03:00
BX_DEBUG(("local apic timer(one-shot) triggered int"));
2005-04-26 22:30:30 +04:00
bx_pc_system.deactivate_timer(timer_handle);
}
}
2006-03-02 23:17:54 +03:00
void bx_local_apic_c::set_divide_configuration(Bit32u value)
{
BX_ASSERT(value == (value & 0x0b));
// move bit 3 down to bit 0.
value = ((value & 8) >> 1) | (value & 3);
BX_ASSERT(value >= 0 && value <= 7);
2009-02-20 20:05:03 +03:00
timer_divide_factor = (value==7) ? 1 : (2 << value);
BX_INFO(("set timer divide factor to %d", timer_divide_factor));
2006-03-02 23:17:54 +03:00
}
void bx_local_apic_c::set_initial_timer_count(Bit32u value)
{
// If active before, deactive the current timer before changing it.
2006-03-02 23:09:21 +03:00
if(timer_active) {
bx_pc_system.deactivate_timer(timer_handle);
timer_active = 0;
}
timer_initial = value;
timer_current = 0;
2006-03-02 23:09:21 +03:00
if(timer_initial != 0) // terminate the counting if timer_initial = 0
{
// This should trigger the counter to start. If already started,
// restart from the new start value.
2006-06-01 15:59:23 +04:00
BX_DEBUG(("APIC: Initial Timer Count Register = %u", value));
timer_current = timer_initial;
timer_active = 1;
Bit32u timervec = lvt[APIC_LVT_TIMER];
2006-03-02 23:17:54 +03:00
bx_bool continuous = (timervec & 0x20000) > 0;
ticksInitial = bx_pc_system.time_ticks(); // Take a reading.
bx_pc_system.activate_timer_ticks(timer_handle,
Bit64u(timer_initial) * Bit64u(timer_divide_factor), continuous);
}
}
2010-04-08 19:50:39 +04:00
#if BX_SUPPORT_X2APIC
// return false when x2apic is not supported/not readable
bx_bool bx_local_apic_c::read_x2apic(unsigned index, Bit64u *val_64)
{
index = (index - 0x800) << 4;
switch(index) {
// return full 32-bit lapic id
case BX_LAPIC_ID:
*val_64 = apic_id;
break;
case BX_LAPIC_LDR:
*val_64 = ldr;
break;
// full 64-bit access to ICR
case BX_LAPIC_ICR_LO:
*val_64 = ((Bit64u) icr_lo) | (((Bit64u) icr_hi) << 32);
break;
// not supported/not readable in x2apic mode
case BX_LAPIC_ARBITRATION_PRIORITY:
case BX_LAPIC_DESTINATION_FORMAT:
case BX_LAPIC_ICR_HI:
case BX_LAPIC_EOI: // write only
case BX_LAPIC_SELF_IPI: // write only
return 0;
// compatible to legacy lapic mode
case BX_LAPIC_VERSION:
case BX_LAPIC_TPR:
case BX_LAPIC_PPR:
case BX_LAPIC_SPURIOUS_VECTOR:
case BX_LAPIC_ISR1:
case BX_LAPIC_ISR2:
case BX_LAPIC_ISR3:
case BX_LAPIC_ISR4:
case BX_LAPIC_ISR5:
case BX_LAPIC_ISR6:
case BX_LAPIC_ISR7:
case BX_LAPIC_ISR8:
case BX_LAPIC_TMR1:
case BX_LAPIC_TMR2:
case BX_LAPIC_TMR3:
case BX_LAPIC_TMR4:
case BX_LAPIC_TMR5:
case BX_LAPIC_TMR6:
case BX_LAPIC_TMR7:
case BX_LAPIC_TMR8:
case BX_LAPIC_IRR1:
case BX_LAPIC_IRR2:
case BX_LAPIC_IRR3:
case BX_LAPIC_IRR4:
case BX_LAPIC_IRR5:
case BX_LAPIC_IRR6:
case BX_LAPIC_IRR7:
case BX_LAPIC_IRR8:
case BX_LAPIC_ESR:
case BX_LAPIC_LVT_TIMER:
case BX_LAPIC_LVT_THERMAL:
case BX_LAPIC_LVT_PERFMON:
case BX_LAPIC_LVT_LINT0:
case BX_LAPIC_LVT_LINT1:
case BX_LAPIC_LVT_ERROR:
case BX_LAPIC_TIMER_INITIAL_COUNT:
case BX_LAPIC_TIMER_CURRENT_COUNT:
case BX_LAPIC_TIMER_DIVIDE_CFG:
*val_64 = read_aligned(index);
break;
default:
BX_DEBUG(("read_x2apic: not supported apic register 0x%08x", index));
return 0;
}
return 1;
}
// return false when x2apic is not supported/not writeable
bx_bool bx_local_apic_c::write_x2apic(unsigned index, Bit64u val_64)
{
Bit32u val32_lo = GET32L(val_64);
index = (index - 0x800) << 4;
switch(index) {
// read only/not available in x2apic mode
case BX_LAPIC_ID:
case BX_LAPIC_VERSION:
case BX_LAPIC_ARBITRATION_PRIORITY:
case BX_LAPIC_PPR:
case BX_LAPIC_LDR:
case BX_LAPIC_DESTINATION_FORMAT:
case BX_LAPIC_ISR1:
case BX_LAPIC_ISR2:
case BX_LAPIC_ISR3:
case BX_LAPIC_ISR4:
case BX_LAPIC_ISR5:
case BX_LAPIC_ISR6:
case BX_LAPIC_ISR7:
case BX_LAPIC_ISR8:
case BX_LAPIC_TMR1:
case BX_LAPIC_TMR2:
case BX_LAPIC_TMR3:
case BX_LAPIC_TMR4:
case BX_LAPIC_TMR5:
case BX_LAPIC_TMR6:
case BX_LAPIC_TMR7:
case BX_LAPIC_TMR8:
case BX_LAPIC_IRR1:
case BX_LAPIC_IRR2:
case BX_LAPIC_IRR3:
case BX_LAPIC_IRR4:
case BX_LAPIC_IRR5:
case BX_LAPIC_IRR6:
case BX_LAPIC_IRR7:
case BX_LAPIC_IRR8:
case BX_LAPIC_ICR_HI:
case BX_LAPIC_TIMER_CURRENT_COUNT:
return 0;
// send self ipi
case BX_LAPIC_SELF_IPI:
trigger_irq(val32_lo & 0xff, APIC_EDGE_TRIGGERED);
break;
// handle full 64-bit write
case BX_LAPIC_ICR_LO:
send_ipi(GET32H(val_64), val32_lo);
break;
case BX_LAPIC_TPR:
// handle reserved bits, only bits 0-7 are writeable
if ((val32_lo & 0xffffff00) != 0)
return 0;
break; // use legacy write
case BX_LAPIC_SPURIOUS_VECTOR:
// handle reserved bits, only bits 0-8, 12 are writeable
// we do not support directed EOI capability, so reserve bit 12 as well
if ((val32_lo & 0xfffffe00) != 0)
return 0;
break; // use legacy write
case BX_LAPIC_EOI:
case BX_LAPIC_ESR:
if (val_64 != 0) return 0;
break; // use legacy write
case BX_LAPIC_LVT_TIMER:
case BX_LAPIC_LVT_THERMAL:
case BX_LAPIC_LVT_PERFMON:
case BX_LAPIC_LVT_LINT0:
case BX_LAPIC_LVT_LINT1:
case BX_LAPIC_LVT_ERROR:
case BX_LAPIC_TIMER_INITIAL_COUNT:
case BX_LAPIC_TIMER_DIVIDE_CFG:
break; // use legacy write
default:
BX_DEBUG(("write_x2apic: not supported apic register 0x%08x", index));
return 0;
}
if (GET32H(val_64) != 0) // upper 32-bit are reserved for all x2apic MSRs
return 0;
write_aligned(index, val32_lo);
return 1;
}
#endif
2006-05-27 19:54:49 +04:00
void bx_local_apic_c::register_state(bx_param_c *parent)
{
unsigned i;
char name[6];
bx_list_c *lapic = new bx_list_c(parent, "local_apic", 25);
BXRS_HEX_PARAM_SIMPLE(lapic, base_addr);
2009-02-20 20:05:03 +03:00
BXRS_HEX_PARAM_SIMPLE(lapic, apic_id);
2009-02-20 02:19:11 +03:00
BXRS_HEX_PARAM_SIMPLE(lapic, mode);
BXRS_HEX_PARAM_SIMPLE(lapic, spurious_vector);
BXRS_PARAM_BOOL(lapic, software_enabled, software_enabled);
BXRS_PARAM_BOOL(lapic, focus_disable, focus_disable);
BXRS_HEX_PARAM_SIMPLE(lapic, task_priority);
2009-02-20 02:19:11 +03:00
BXRS_HEX_PARAM_SIMPLE(lapic, ldr);
BXRS_HEX_PARAM_SIMPLE(lapic, dest_format);
2008-02-03 00:46:54 +03:00
bx_list_c *ISR = new bx_list_c(lapic, "isr", BX_LAPIC_MAX_INTS);
bx_list_c *TMR = new bx_list_c(lapic, "tmr", BX_LAPIC_MAX_INTS);
bx_list_c *IRR = new bx_list_c(lapic, "irr", BX_LAPIC_MAX_INTS);
for (i=0; i<BX_LAPIC_MAX_INTS; i++) {
2006-05-27 19:54:49 +04:00
sprintf(name, "0x%02x", i);
new bx_shadow_num_c(ISR, name, &isr[i]);
new bx_shadow_num_c(TMR, name, &tmr[i]);
new bx_shadow_num_c(IRR, name, &irr[i]);
2006-05-27 19:54:49 +04:00
}
BXRS_HEX_PARAM_SIMPLE(lapic, error_status);
BXRS_HEX_PARAM_SIMPLE(lapic, shadow_error_status);
BXRS_HEX_PARAM_SIMPLE(lapic, icr_hi);
BXRS_HEX_PARAM_SIMPLE(lapic, icr_lo);
bx_list_c *LVT = new bx_list_c(lapic, "lvt", APIC_LVT_ENTRIES);
2006-05-28 01:44:40 +04:00
for (i=0; i<APIC_LVT_ENTRIES; i++) {
2006-05-27 19:54:49 +04:00
sprintf(name, "%d", i);
new bx_shadow_num_c(LVT, name, &lvt[i], BASE_HEX);
2006-05-27 19:54:49 +04:00
}
BXRS_HEX_PARAM_SIMPLE(lapic, timer_initial);
BXRS_HEX_PARAM_SIMPLE(lapic, timer_current);
BXRS_HEX_PARAM_SIMPLE(lapic, timer_divconf);
BXRS_DEC_PARAM_SIMPLE(lapic, timer_divide_factor);
2009-11-02 18:00:47 +03:00
BXRS_DEC_PARAM_SIMPLE(lapic, timer_handle);
BXRS_PARAM_BOOL(lapic, timer_active, timer_active);
BXRS_HEX_PARAM_SIMPLE(lapic, ticksInitial);
BXRS_PARAM_BOOL(lapic, INTR, INTR);
2006-05-27 19:54:49 +04:00
}
- apply patch.ifdef-disabled-options. Comments from that patch are below: For a whole lot of configure options, I put #if...#endif around code that is specific to the option, even in files which are normally only compiled when the option is on. This allows me to create a MS Visual C++ 6.0 workspace that supports many of these options. The workspace will basically compile every file all the time, but the code for disabled options will be commented out by the #if...#endif. This may one day lead to simplification of the Makefiles and configure scripts, but for the moment I'm leaving Makefiles and configure scripts alone. Affected options: BX_SUPPORT_APIC (cpu/apic.cc) BX_SUPPORT_X86_64 (cpu/*64.cc) BX_DEBUGGER (debug/*) BX_DISASM (disasm/*) BX_WITH_nameofgui (gui/*) BX_SUPPORT_CDROM (iodev/cdrom.cc) BX_NE2K_SUPPORT (iodev/eth*.cc, iodev/ne2k.cc) BX_SUPPORT_APIC (iodev/ioapic.cc) BX_IODEBUG_SUPPORT (iodev/iodebug.cc) BX_PCI_SUPPORT (iodev/pci*.cc) BX_SUPPORT_SB16 (iodev/sb*.cc) Modified Files: cpu/apic.cc cpu/arith64.cc cpu/ctrl_xfer64.cc cpu/data_xfer64.cc cpu/fetchdecode64.cc cpu/logical64.cc cpu/mult64.cc cpu/resolve64.cc cpu/shift64.cc cpu/stack64.cc debug/Makefile.in debug/crc.cc debug/dbg_main.cc debug/lexer.l debug/linux.cc debug/parser.c debug/parser.y disasm/dis_decode.cc disasm/dis_groups.cc gui/amigaos.cc gui/beos.cc gui/carbon.cc gui/macintosh.cc gui/rfb.cc gui/sdl.cc gui/term.cc gui/win32.cc gui/wx.cc gui/wxdialog.cc gui/wxmain.cc gui/x.cc iodev/cdrom.cc iodev/eth.cc iodev/eth_arpback.cc iodev/eth_fbsd.cc iodev/eth_linux.cc iodev/eth_null.cc iodev/eth_packetmaker.cc iodev/eth_tap.cc iodev/eth_tuntap.cc iodev/eth_win32.cc iodev/ioapic.cc iodev/iodebug.cc iodev/ne2k.cc iodev/pci.cc iodev/pci2isa.cc iodev/sb16.cc iodev/soundlnx.cc iodev/soundwin.cc
2002-11-19 08:47:45 +03:00
#endif /* if BX_SUPPORT_APIC */