- added I/O APIC and local APICs
- for more details, see BRANCH-smp-bochs
This commit is contained in:
parent
17f0f589ba
commit
af4ccaae3e
@ -40,6 +40,7 @@ RANLIB = @RANLIB@
|
||||
VIDEO_OBJS_VGA = vga.o
|
||||
VIDEO_OBJS_HGA = hga.o
|
||||
VIDEO_OBJS = @VIDEO_OBJS@
|
||||
IOAPIC_OBJS = @IOAPIC_OBJS@
|
||||
|
||||
BX_INCDIRS = @DASH@I.. -I../@INSTRUMENT_DIR@
|
||||
LOCAL_CXXFLAGS = $(MCH_CFLAGS)
|
||||
@ -67,7 +68,8 @@ BX_HW_IODEV_OBJS = \
|
||||
@NE2K_OBJS@ \
|
||||
@CDROM_OBJS@ \
|
||||
@SB16_OBJS@ \
|
||||
$(MCH_OBJS)
|
||||
$(MCH_OBJS) \
|
||||
$(IOAPIC_OBJS)
|
||||
|
||||
|
||||
BX_IODEV_OBJS = $(BX_HW_IODEV_OBJS)
|
||||
|
@ -97,8 +97,9 @@ bx_devices_c::~bx_devices_c(void)
|
||||
|
||||
|
||||
void
|
||||
bx_devices_c::init(void)
|
||||
bx_devices_c::init(BX_MEM_C *newmem)
|
||||
{
|
||||
mem = newmem;
|
||||
// Start with all IO port address registered to unmapped handler
|
||||
// MUST be called first
|
||||
unmapped = &bx_unmapped;
|
||||
@ -111,6 +112,13 @@ bx_devices_c::init(void)
|
||||
pci->reset();
|
||||
#endif
|
||||
|
||||
#if BX_APIC_SUPPORT
|
||||
// I/O APIC 82093AA
|
||||
ioapic = & bx_ioapic;
|
||||
ioapic->init ();
|
||||
ioapic->set_id (BX_IOAPIC_DEFAULT_ID);
|
||||
#endif
|
||||
|
||||
|
||||
// CMOS RAM & RTC
|
||||
cmos = &bx_cmos;
|
||||
@ -190,7 +198,7 @@ bx_devices_c::init(void)
|
||||
"Port 92h System Control" );
|
||||
|
||||
// misc. CMOS
|
||||
Bit16u extended_memory_in_k = BX_MEM.get_memory_in_k() - 1024;
|
||||
Bit16u extended_memory_in_k = mem->get_memory_in_k() - 1024;
|
||||
cmos->s.reg[0x15] = (Bit8u) BASE_MEMORY_IN_K;
|
||||
cmos->s.reg[0x16] = (Bit8u) (BASE_MEMORY_IN_K >> 8);
|
||||
cmos->s.reg[0x17] = (Bit8u) extended_memory_in_k;
|
||||
@ -289,6 +297,13 @@ bx_devices_c::timer()
|
||||
}
|
||||
if (retval & 0x02)
|
||||
pic->trigger_irq(12);
|
||||
|
||||
#if BX_APIC_SUPPORT
|
||||
// update local APIC timers
|
||||
for (int i=0; i<BX_SMP_PROCESSORS; i++) {
|
||||
BX_CPU(i)->local_apic.periodic (TIMER_DELTA);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -2430,7 +2430,7 @@ int concat_image_t::open (const char* pathname0)
|
||||
BX_PANIC(("fstat() returns error!\n"));
|
||||
}
|
||||
if ((stat_buf.st_size % 512) != 0) {
|
||||
BX_PANIC(("size of disk image must be multiple of 512 bytes"));
|
||||
BX_PANIC(("size of disk image must be multiple of 512 bytes\n"));
|
||||
}
|
||||
length_table[i] = stat_buf.st_size;
|
||||
start_offset_table[i] = start_offset;
|
||||
@ -2457,7 +2457,7 @@ void concat_image_t::close ()
|
||||
off_t concat_image_t::lseek (off_t offset, int whence)
|
||||
{
|
||||
if ((offset % 512) != 0)
|
||||
BX_PANIC( ("lseek HD with offset not multiple of 512"));
|
||||
BX_PANIC( ("lseek HD with offset not multiple of 512\n"));
|
||||
if (bx_dbg.disk)
|
||||
BX_INFO(("concat_image_t.lseek(%d)\n", whence));
|
||||
// is this offset in this disk image?
|
||||
@ -2505,7 +2505,7 @@ ssize_t concat_image_t::read (void* buf, size_t count)
|
||||
// This can be supported pretty easily, but needs additional checks for
|
||||
// end of a partial image.
|
||||
if (!seek_was_last_op)
|
||||
BX_PANIC( ("disk: no seek before read"));
|
||||
BX_PANIC( ("disk: no seek before read\n"));
|
||||
return ::read(fd, buf, count);
|
||||
}
|
||||
|
||||
@ -2517,7 +2517,7 @@ ssize_t concat_image_t::write (const void* buf, size_t count)
|
||||
// This can be supported pretty easily, but needs additional checks for
|
||||
// end of a partial image.
|
||||
if (!seek_was_last_op)
|
||||
BX_PANIC( ("disk: no seek before write"));
|
||||
BX_PANIC( ("disk: no seek before write\n"));
|
||||
return ::write(fd, buf, count);
|
||||
}
|
||||
#endif /* BX_SPLIT_HD_SUPPORT */
|
||||
|
170
bochs/iodev/ioapic.cc
Normal file
170
bochs/iodev/ioapic.cc
Normal file
@ -0,0 +1,170 @@
|
||||
#include <stdio.h>
|
||||
#include "bochs.h"
|
||||
|
||||
class bx_ioapic_c bx_ioapic;
|
||||
#define LOG_THIS bx_ioapic.
|
||||
|
||||
void
|
||||
bx_io_redirect_entry_t::parse_value ()
|
||||
{
|
||||
dest = (value >> 56) & 0xff;
|
||||
masked = (value >> 16) & 1;
|
||||
trig_mode = (value >> 15) & 1;
|
||||
remote_irr = (value >> 14) & 1;
|
||||
polarity = (value >> 13) & 1;
|
||||
//delivery_status = (value >> 12) & 1;
|
||||
delivery_status = 0; // always say the message has gone through
|
||||
dest_mode = (value >> 11) & 1;
|
||||
delivery_mode = (value >> 8) & 7;
|
||||
vector = (value >> 0) & 0xff;
|
||||
}
|
||||
|
||||
void
|
||||
bx_io_redirect_entry_t::sprintf_self (char *buf)
|
||||
{
|
||||
sprintf (buf, "dest=%02x, masked=%d, trig_mode=%d, remote_irr=%d, polarity=%d, delivery_status=%d, dest_mode=%d, delivery_mode=%d, vector=%02x", dest, masked, trig_mode, remote_irr, polarity, delivery_status, dest_mode, delivery_mode, vector);
|
||||
}
|
||||
|
||||
bx_ioapic_c::bx_ioapic_c ()
|
||||
: bx_generic_apic_c ()
|
||||
{
|
||||
setprefix("[IOAP]");
|
||||
settype(IOAPICLOG);
|
||||
}
|
||||
|
||||
bx_ioapic_c::~bx_ioapic_c () {
|
||||
}
|
||||
|
||||
void
|
||||
bx_ioapic_c::init ()
|
||||
{
|
||||
bx_generic_apic_c::init ();
|
||||
if (bx_dbg.ioapic)
|
||||
BX_INFO(("initializing I/O APIC\n"));
|
||||
base_addr = 0xfec00000;
|
||||
ioregsel = 0;
|
||||
// all interrupts masked
|
||||
for (int i=0; i<BX_IOAPIC_NUM_PINS; i++) {
|
||||
ioredtbl[i].set_even_word (0x00010000);
|
||||
ioredtbl[i].set_odd_word (0x00000000);
|
||||
}
|
||||
irr = 0;
|
||||
}
|
||||
|
||||
void
|
||||
bx_ioapic_c::read_aligned(Bit32u address, Bit32u *data, unsigned len)
|
||||
{
|
||||
if (bx_dbg.ioapic)
|
||||
BX_INFO( ("I/O APIC read_aligned addr=%08x, len=%d\n", address, len));
|
||||
BX_ASSERT (len == 4);
|
||||
address &= 0xff;
|
||||
if (address == 0x00) {
|
||||
// select register
|
||||
*data = ioregsel;
|
||||
return;
|
||||
} else if (address != 0x10) {
|
||||
BX_PANIC(("IOAPIC: read from unsupported address\n"));
|
||||
}
|
||||
// only reached when reading data register
|
||||
switch (ioregsel) {
|
||||
case 0x00: // APIC ID
|
||||
*data = ((id & 0xf) << 24);
|
||||
return;
|
||||
case 0x01: // version
|
||||
*data = (((BX_IOAPIC_NUM_PINS-1) & 0xff) << 16)
|
||||
| (BX_IOAPIC_VERSION_ID & 0x0f);
|
||||
return;
|
||||
case 0x02:
|
||||
BX_INFO(("IOAPIC: arbitration ID unsupported, returned 0\n"));
|
||||
*data = 0;
|
||||
return;
|
||||
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_odd_word() : entry->get_even_word ();
|
||||
return;
|
||||
}
|
||||
BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x\n", ioregsel));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bx_ioapic_c::write(Bit32u address, Bit32u *value, unsigned len)
|
||||
{
|
||||
if (bx_dbg.ioapic)
|
||||
BX_INFO(("IOAPIC: write addr=%08x, data=%08x, len=%d\n", address, *value, len));
|
||||
address &= 0xff;
|
||||
if (address == 0x00) {
|
||||
ioregsel = *value;
|
||||
return;
|
||||
} else if (address != 0x10) {
|
||||
BX_PANIC(("IOAPIC: write to unsupported address\n"));
|
||||
}
|
||||
// only reached when writing data register
|
||||
switch (ioregsel) {
|
||||
case 0x00: // set APIC ID
|
||||
{
|
||||
Bit8u newid = (*value >> 24) & 0xf;
|
||||
BX_INFO(("IOAPIC: setting id to 0x%x\n", newid));
|
||||
set_id (newid);
|
||||
return;
|
||||
}
|
||||
case 0x01: // version
|
||||
case 0x02: // arbitration id
|
||||
BX_INFO(("IOAPIC: could not write, IOREGSEL=0x%02x\n", ioregsel));
|
||||
return;
|
||||
default:
|
||||
int index = (ioregsel - 0x10) >> 1;
|
||||
if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
|
||||
bx_io_redirect_entry_t *entry = ioredtbl + index;
|
||||
if (ioregsel&1)
|
||||
entry->set_odd_word (*value);
|
||||
else
|
||||
entry->set_even_word (*value);
|
||||
char buf[1024];
|
||||
entry->sprintf_self (buf);
|
||||
if (bx_dbg.ioapic)
|
||||
BX_INFO(("IOAPIC: now entry[%d] is %s\n", index, buf));
|
||||
service_ioapic ();
|
||||
return;
|
||||
}
|
||||
BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x\n", ioregsel));
|
||||
}
|
||||
}
|
||||
|
||||
void bx_ioapic_c::trigger_irq (unsigned vector, unsigned from)
|
||||
{
|
||||
if (bx_dbg.ioapic)
|
||||
BX_INFO(("IOAPIC: received interrupt %d\n", vector));
|
||||
if (vector >= 0 && vector < BX_IOAPIC_NUM_PINS) {
|
||||
Bit32u bit = 1<<vector;
|
||||
if ((irr & bit) == 0) {
|
||||
irr |= bit;
|
||||
service_ioapic ();
|
||||
}
|
||||
} else BX_PANIC(("IOAPIC: vector %d out of range\n", vector));
|
||||
}
|
||||
|
||||
void bx_ioapic_c::untrigger_irq (unsigned num, unsigned from)
|
||||
{
|
||||
if (bx_dbg.ioapic)
|
||||
BX_INFO(("IOAPIC: interrupt %d went away\n", num));
|
||||
}
|
||||
|
||||
void bx_ioapic_c::service_ioapic ()
|
||||
{
|
||||
// look in IRR and deliver any interrupts that are not masked.
|
||||
if (bx_dbg.ioapic)
|
||||
BX_INFO(("IOAPIC: servicing\n"));
|
||||
for (unsigned bit=0; bit < BX_IOAPIC_NUM_PINS; bit++) {
|
||||
if (irr & (1<<bit)) {
|
||||
bx_io_redirect_entry_t *entry = ioredtbl + bit;
|
||||
if (!entry->masked) {
|
||||
// clear irr bit and deliver
|
||||
Boolean done = deliver (entry->dest, entry->dest_mode, entry->delivery_mode, entry->vector, entry->polarity, entry->trig_mode);
|
||||
if (done) irr &= ~(1<<bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
49
bochs/iodev/ioapic.h
Normal file
49
bochs/iodev/ioapic.h
Normal file
@ -0,0 +1,49 @@
|
||||
extern class bx_ioapic_c bx_ioapic;
|
||||
|
||||
#define BX_IOAPIC_VERSION_ID 0x00170011 // same version as 82093 IOAPIC
|
||||
#define BX_IOAPIC_NUM_PINS 0x18
|
||||
|
||||
class bx_io_redirect_entry_t {
|
||||
Bit64u value;
|
||||
public:
|
||||
Bit32u get_even_word () { return value & 0xffffffff; }
|
||||
Bit32u get_odd_word () { return (value>>32) & 0xffffffff; }
|
||||
void set_even_word (Bit32u even) {
|
||||
// keep high 32 bits of value, replace low 32
|
||||
value = ((value >> 32) << 32) | (even & 0xffffffff);
|
||||
parse_value ();
|
||||
}
|
||||
void set_odd_word (Bit32u odd) {
|
||||
// keep low 32 bits of value, replace high 32
|
||||
value = (((Bit64u)odd & 0xffffffff) << 32) | (value & 0xffffffff);
|
||||
parse_value ();
|
||||
}
|
||||
void parse_value ();
|
||||
// parse_value sets the value and all the fields below. Do not change
|
||||
// these fields except by calling parse_value.
|
||||
Bit8u dest, masked, trig_mode, remote_irr, polarity, delivery_status, dest_mode, delivery_mode, vector;
|
||||
void sprintf_self (char *buf);
|
||||
};
|
||||
|
||||
class bx_ioapic_c : public bx_generic_apic_c {
|
||||
Bit32u ioregsel; // selects between various registers
|
||||
// interrupt request bitmask, not visible from the outside. Bits in the
|
||||
// irr are set when trigger_irq is called, and cleared when the interrupt
|
||||
// is delivered to the processor. If an interrupt is masked, the irr
|
||||
// will still be set but delivery will not occur until it is unmasked.
|
||||
// It's not clear if this is how the real device works.
|
||||
Bit32u irr;
|
||||
public:
|
||||
bx_io_redirect_entry_t ioredtbl[BX_IOAPIC_NUM_PINS]; // table of redirections
|
||||
bx_ioapic_c ();
|
||||
~bx_ioapic_c ();
|
||||
virtual void init ();
|
||||
virtual void read_aligned(Bit32u address, Bit32u *data, unsigned len);
|
||||
virtual void write(Bit32u address, Bit32u *value, unsigned len);
|
||||
void trigger_irq (unsigned num, unsigned from);
|
||||
void untrigger_irq (unsigned num, unsigned from);
|
||||
void service_ioapic ();
|
||||
virtual Boolean match_logical_addr (Bit8u address) { return false; }
|
||||
virtual Boolean is_local_apic () { return false; }
|
||||
virtual bx_apic_type_t get_type () { return APIC_TYPE_IOAPIC; }
|
||||
};
|
@ -47,6 +47,7 @@ class bx_pic_c;
|
||||
class bx_hard_drive_c;
|
||||
class bx_sb16_c;
|
||||
class bx_pci_c;
|
||||
class bx_ioapic_c;
|
||||
class bx_ne2k_c;
|
||||
class bx_g2h_c;
|
||||
|
||||
@ -70,7 +71,8 @@ class bx_devices_c : public logfunctions {
|
||||
public:
|
||||
bx_devices_c(void);
|
||||
~bx_devices_c(void);
|
||||
void init(void);
|
||||
void init(BX_MEM_C *);
|
||||
BX_MEM_C *mem; // address space associated with these devices
|
||||
void register_io_read_handler(void *this_ptr, bx_read_handler_t f, Bit32u addr, const char *name );
|
||||
void register_io_write_handler(void *this_ptr, bx_write_handler_t f, Bit32u addr, const char *name );
|
||||
void register_irq(unsigned irq, const char *name);
|
||||
@ -86,6 +88,7 @@ public:
|
||||
static void timer_handler(void *);
|
||||
void timer(void);
|
||||
|
||||
bx_ioapic_c *ioapic;
|
||||
bx_pci_c *pci;
|
||||
bx_pit_c *pit;
|
||||
bx_keyb_c *keyboard;
|
||||
@ -139,6 +142,9 @@ private:
|
||||
#else
|
||||
# include "iodev/hga.h"
|
||||
#endif
|
||||
#if BX_APIC_SUPPORT
|
||||
# include "iodev/ioapic.h"
|
||||
#endif
|
||||
#include "iodev/cmos.h"
|
||||
#include "iodev/dma.h"
|
||||
#include "iodev/floppy.h"
|
||||
|
@ -535,7 +535,10 @@ BX_PANIC(("kbd: OUTB set and command 0x%02x encountered\n", value));
|
||||
case 0xfe: // System Reset, transition to real mode
|
||||
BX_INFO(("system reset\n"));
|
||||
bx_pc_system.ResetSignal( PCS_SET ); /* XXX is this right? */
|
||||
BX_CPU.reset(BX_RESET_HARDWARE);
|
||||
{
|
||||
for (int i=0; i<BX_SMP_PROCESSORS; i++)
|
||||
BX_CPU(i)->reset(BX_RESET_HARDWARE);
|
||||
}
|
||||
// Use bx_pc_system if necessary bx_cpu.reset_cpu();
|
||||
// bx_pc_system.ResetSignal( PCS_SET );
|
||||
break;
|
||||
|
@ -395,17 +395,17 @@ bx_pci_c::print_i440fx_state()
|
||||
bx_pci_c::i440fx_fetch_ptr(Bit32u addr)
|
||||
{
|
||||
if (bx_options.i440FXSupport) {
|
||||
switch (bx_pci.rd_memType (addr)) {
|
||||
switch (rd_memType (addr)) {
|
||||
case 0x0: // Read from ShadowRAM
|
||||
return (&BX_MEM.vector[addr]);
|
||||
return (&devices->mem->vector[addr]);
|
||||
|
||||
case 0x1: // Read from ROM
|
||||
return (&bx_pci.s.i440fx.shadow[(addr - 0xc0000)]);
|
||||
return (&s.i440fx.shadow[(addr - 0xc0000)]);
|
||||
default:
|
||||
BX_PANIC(("i440fx_fetch_ptr(): default case\n"));
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
return (&BX_MEM.vector[addr]);
|
||||
return (&devices->mem->vector[addr]);
|
||||
}
|
||||
|
@ -497,6 +497,11 @@ bx_pic_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
||||
void
|
||||
bx_pic_c::trigger_irq(unsigned irq_no)
|
||||
{
|
||||
#if BX_APIC_SUPPORT
|
||||
// forward this function call to the ioapic too
|
||||
BX_PIC_THIS devices->ioapic->trigger_irq (irq_no, -1);
|
||||
#endif
|
||||
|
||||
int irq_no_bitmask;
|
||||
|
||||
#if BX_DEBUG
|
||||
@ -522,6 +527,11 @@ bx_pic_c::trigger_irq(unsigned irq_no)
|
||||
void
|
||||
bx_pic_c::untrigger_irq(unsigned irq_no)
|
||||
{
|
||||
#if BX_APIC_SUPPORT
|
||||
// forward this function call to the ioapic too
|
||||
BX_PIC_THIS devices->ioapic->untrigger_irq (irq_no, -1);
|
||||
#endif
|
||||
|
||||
int irq_no_bitmask;
|
||||
|
||||
#if BX_DEBUG
|
||||
|
@ -91,7 +91,7 @@ bx_sb16_c::~bx_sb16_c(void)
|
||||
|
||||
delete(DSP.dma.chunk);
|
||||
|
||||
if (bx_options.sb16.loglevel > 0)
|
||||
if ((bx_options.sb16.loglevel > 0) && LOGFILE)
|
||||
fclose(LOGFILE);
|
||||
}
|
||||
|
||||
|
@ -619,7 +619,7 @@ bx_serial_c::rx_timer(void)
|
||||
#endif
|
||||
#endif
|
||||
int bdrate = BX_SER_THIS s[0].baudrate / 8;
|
||||
unsigned char chbuf;
|
||||
unsigned char chbuf = 0;
|
||||
|
||||
tval.tv_sec = 0;
|
||||
tval.tv_usec = 0;
|
||||
|
@ -1405,7 +1405,7 @@ bx_vga_c::mem_read(Bit32u addr)
|
||||
{
|
||||
char value;
|
||||
|
||||
value = BX_MEM.video[addr-0xA0000];
|
||||
value = devices->mem->video[addr-0xA0000];
|
||||
|
||||
return value;
|
||||
}
|
||||
@ -1509,7 +1509,7 @@ bx_vga_c::mem_write(Bit32u addr, Bit8u value)
|
||||
#ifdef __OS2__
|
||||
if ( bx_options.videomode == BX_VIDEO_DIRECT )
|
||||
{
|
||||
BX_MEM.video[addr-0xA0000] = value;
|
||||
devices->mem->video[addr-0xA0000] = value;
|
||||
|
||||
return;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user