mirror of https://github.com/bochs-emu/Bochs
- implementation of the PCI device register mechanism
The new function register_pci_handlers() is similar to the register functions for i/o addresses. A PCI device can register the read/write handlers for it's private PCI configuration space. The i/o mapped registers of the host bridge control the access to the configuration registers of each PCI device. You can select the bus, device, function and register address with the confAddr register. The confData register is a window to the configuration space of the selected device. - reset sets the values of the i/o mapped registers to 0 - changed some BX_INFO messages to BX_DEBUG
This commit is contained in:
parent
d5e43f24b4
commit
1bd3646867
|
@ -1,8 +1,8 @@
|
|||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id: pci.cc,v 1.14 2002-05-10 10:56:04 vruppert Exp $
|
||||
// $Id: pci.cc,v 1.15 2002-05-30 07:33:48 vruppert Exp $
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001 MandrakeSoft S.A.
|
||||
// Copyright (C) 2002 MandrakeSoft S.A.
|
||||
//
|
||||
// MandrakeSoft S.A.
|
||||
// 43, rue d'Aboukir
|
||||
|
@ -45,13 +45,28 @@ bx_pci_c bx_pci;
|
|||
|
||||
bx_pci_c::bx_pci_c(void)
|
||||
{
|
||||
put("PCI");
|
||||
settype(PCILOG);
|
||||
unsigned i;
|
||||
|
||||
put("PCI");
|
||||
settype(PCILOG);
|
||||
|
||||
BX_PCI_THIS num_pci_handles = 0;
|
||||
|
||||
/* set unused elements to appropriate values */
|
||||
for (i=0; i < BX_MAX_PCI_DEVICES; i++) {
|
||||
BX_PCI_THIS pci_handler[i].read = NULL;
|
||||
BX_PCI_THIS pci_handler[i].write = NULL;
|
||||
}
|
||||
|
||||
for (i=0; i < 0x100; i++) {
|
||||
BX_PCI_THIS pci_handler_id[i] = BX_MAX_PCI_DEVICES; // not assigned
|
||||
}
|
||||
}
|
||||
|
||||
bx_pci_c::~bx_pci_c(void)
|
||||
{
|
||||
BX_INFO(("Exit."));
|
||||
// nothing for now
|
||||
BX_DEBUG(("Exit."));
|
||||
}
|
||||
|
||||
|
||||
|
@ -73,6 +88,9 @@ bx_pci_c::init(bx_devices_c *d)
|
|||
d->register_io_write_handler(this, write_handler, i, "i440FX");
|
||||
}
|
||||
|
||||
BX_PCI_THIS register_pci_handlers(this, pci_read_handler, pci_write_handler,
|
||||
0x00, "440FX Host bridge");
|
||||
|
||||
for (unsigned i=0; i<256; i++)
|
||||
BX_PCI_THIS s.i440fx.array[i] = 0x0;
|
||||
}
|
||||
|
@ -87,6 +105,9 @@ bx_pci_c::init(bx_devices_c *d)
|
|||
void
|
||||
bx_pci_c::reset(void)
|
||||
{
|
||||
BX_PCI_THIS s.i440fx.confAddr = 0;
|
||||
BX_PCI_THIS s.i440fx.confData = 0;
|
||||
|
||||
BX_PCI_THIS s.i440fx.array[0x04] = 0x06;
|
||||
BX_PCI_THIS s.i440fx.array[0x05] = 0x00;
|
||||
BX_PCI_THIS s.i440fx.array[0x06] = 0x80;
|
||||
|
@ -144,29 +165,23 @@ bx_pci_c::read(Bit32u address, unsigned io_len)
|
|||
case 0x0CFE:
|
||||
case 0x0CFF:
|
||||
{
|
||||
Bit32u val440fx, retMask;
|
||||
// PMC is bus 0 / device 0 / function 0
|
||||
if ((BX_PCI_THIS s.i440fx.confAddr & 0x80FFFF00) == 0x80000000) {
|
||||
val440fx = BX_PCI_THIS s.i440fx.confData >> ((address & 0x3)*8);
|
||||
Bit32u handle, retval;
|
||||
Bit8u devfunc, regnum;
|
||||
|
||||
switch (io_len) {
|
||||
case 1:
|
||||
retMask = 0xFF; break;
|
||||
case 2:
|
||||
retMask = 0xFFFF; break;
|
||||
case 4:
|
||||
retMask = 0xFFFFFFFF; break;
|
||||
default:
|
||||
retMask = 0xFFFFFFFF; break;
|
||||
}
|
||||
val440fx = (val440fx & retMask);
|
||||
BX_DEBUG(("440FX PMC read register 0x%02x value 0x%08x",
|
||||
(Bit8u)(BX_PCI_THIS s.i440fx.confAddr & 0xfc) + (address & 0x3),
|
||||
val440fx));
|
||||
return val440fx;
|
||||
if ((BX_PCI_THIS s.i440fx.confAddr & 0x80FF0000) == 0x80000000) {
|
||||
devfunc = (BX_PCI_THIS s.i440fx.confAddr >> 8) & 0xff;
|
||||
regnum = (BX_PCI_THIS s.i440fx.confAddr & 0xfc) + (address & 0x03);
|
||||
handle = BX_PCI_THIS pci_handler_id[devfunc];
|
||||
if ((io_len <= 4) && (handle < BX_MAX_PCI_DEVICES))
|
||||
retval = (* BX_PCI_THIS pci_handler[handle].read)
|
||||
(BX_PCI_THIS pci_handler[handle].this_ptr, regnum, io_len);
|
||||
else
|
||||
retval = 0xFFFFFFFF;
|
||||
}
|
||||
else
|
||||
return 0xFFFFFFFF;
|
||||
retval = 0xFFFFFFFF;
|
||||
BX_PCI_THIS s.i440fx.confData = retval;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,20 +213,16 @@ bx_pci_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
|||
switch (address) {
|
||||
case 0xCF8:
|
||||
{
|
||||
Bit8u idx440fx;
|
||||
// confAddr accepts a dword value only
|
||||
if (io_len == 4) {
|
||||
BX_PCI_THIS s.i440fx.confAddr = value;
|
||||
if ((value & 0x80FFFF00) == 0x80000000) {
|
||||
idx440fx = (Bit8u)(value & 0xFC);
|
||||
memcpy(&BX_PCI_THIS s.i440fx.confData, &BX_PCI_THIS s.i440fx.array[idx440fx], 4);
|
||||
BX_DEBUG(("440FX PMC register 0x%02x selected", idx440fx));
|
||||
}
|
||||
else {
|
||||
BX_PCI_THIS s.i440fx.confData = 0xFFFFFFFF;
|
||||
BX_DEBUG(("440FX request for bus 0x%02x device 0x%02x function 0x%02x",
|
||||
(value >> 16) & 0xFF, (value >> 11) & 0x1F, (value >> 8) & 0x07));
|
||||
}
|
||||
if ((value & 0x80FFFF00) == 0x80000000) {
|
||||
BX_DEBUG(("440FX PMC register 0x%02x selected", value & 0xfc));
|
||||
}
|
||||
else if ((value & 0x80000000) == 0x80000000) {
|
||||
BX_DEBUG(("440FX request for bus 0x%02x device 0x%02x function 0x%02x",
|
||||
(value >> 16) & 0xFF, (value >> 11) & 0x1F, (value >> 8) & 0x07));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -221,32 +232,22 @@ bx_pci_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
|||
case 0xCFE:
|
||||
case 0xCFF:
|
||||
{
|
||||
Bit8u max_len, idx440fx;
|
||||
Bit32u handle;
|
||||
Bit8u devfunc, regnum;
|
||||
|
||||
idx440fx = (Bit8u)((BX_PCI_THIS s.i440fx.confAddr & 0xFC) + (address & 0x3));
|
||||
max_len = 4 - (address & 0x3);
|
||||
if (io_len < max_len) max_len = io_len;
|
||||
if ((BX_PCI_THIS s.i440fx.confAddr & 0x80FFFF00) == 0x80000000) {
|
||||
for (unsigned i=0; i<max_len; i++) {
|
||||
switch (idx440fx+i) {
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
case 0x06:
|
||||
case 0x08:
|
||||
case 0x09:
|
||||
case 0x0a:
|
||||
case 0x0b:
|
||||
case 0x0e:
|
||||
break;
|
||||
default:
|
||||
BX_PCI_THIS s.i440fx.array[idx440fx+i] = (value >> (i*8)) & 0xFF;
|
||||
BX_DEBUG(("440FX PMC write register 0x%02x value 0x%02x",
|
||||
idx440fx, (value >> (i*8)) & 0xFF));
|
||||
if ((BX_PCI_THIS s.i440fx.confAddr & 0x80FF0000) == 0x80000000) {
|
||||
devfunc = (BX_PCI_THIS s.i440fx.confAddr >> 8) & 0xff;
|
||||
regnum = (BX_PCI_THIS s.i440fx.confAddr & 0xfc) + (address & 0x03);
|
||||
handle = BX_PCI_THIS pci_handler_id[devfunc];
|
||||
if ((io_len <= 4) && (handle < BX_MAX_PCI_DEVICES)) {
|
||||
if (((regnum>=4) && (regnum<=7)) || (regnum==12) || (regnum==13) || (regnum>14)) {
|
||||
(* BX_PCI_THIS pci_handler[handle].write)
|
||||
(BX_PCI_THIS pci_handler[handle].this_ptr, regnum, value, io_len);
|
||||
BX_PCI_THIS s.i440fx.confData = value << (8 * (address & 0x03));
|
||||
}
|
||||
else
|
||||
BX_DEBUG(("read only register, write ignored"));
|
||||
}
|
||||
memcpy(&BX_PCI_THIS s.i440fx.confData, &BX_PCI_THIS s.i440fx.array[idx440fx], 4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -257,6 +258,76 @@ bx_pci_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
|||
}
|
||||
|
||||
|
||||
// static pci configuration space read callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
Bit32u
|
||||
bx_pci_c::pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_PCI_SMF
|
||||
bx_pci_c *class_ptr = (bx_pci_c *) this_ptr;
|
||||
|
||||
return( class_ptr->pci_read(address, io_len) );
|
||||
}
|
||||
|
||||
|
||||
Bit32u
|
||||
bx_pci_c::pci_read(Bit8u address, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_PCI_SMF
|
||||
|
||||
Bit32u val440fx = 0;
|
||||
|
||||
if (io_len <= 4) {
|
||||
memcpy(&val440fx, &BX_PCI_THIS s.i440fx.array[address], io_len);
|
||||
BX_DEBUG(("440FX PMC read register 0x%02x value 0x%08x", address, val440fx));
|
||||
return val440fx;
|
||||
}
|
||||
else
|
||||
return(0xffffffff);
|
||||
}
|
||||
|
||||
|
||||
// static pci configuration space write callback handler
|
||||
// redirects to non-static class handler to avoid virtual functions
|
||||
|
||||
void
|
||||
bx_pci_c::pci_write_handler(void *this_ptr, Bit8u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#if !BX_USE_PCI_SMF
|
||||
bx_pci_c *class_ptr = (bx_pci_c *) this_ptr;
|
||||
|
||||
class_ptr->pci_write(address, value, io_len);
|
||||
}
|
||||
|
||||
void
|
||||
bx_pci_c::pci_write(Bit8u address, Bit32u value, unsigned io_len)
|
||||
{
|
||||
#else
|
||||
UNUSED(this_ptr);
|
||||
#endif // !BX_USE_PCI_SMF
|
||||
|
||||
Bit8u value8;
|
||||
|
||||
if (io_len <= 4) {
|
||||
for (unsigned i=0; i<io_len; i++) {
|
||||
value8 = (value >> (i*8)) & 0xFF;
|
||||
switch (address+i) {
|
||||
case 0x06:
|
||||
case 0x0c:
|
||||
break;
|
||||
default:
|
||||
BX_PCI_THIS s.i440fx.array[address+i] = value8;
|
||||
BX_DEBUG(("440FX PMC write register 0x%02x value 0x%02x", address,
|
||||
value8));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Bit32u
|
||||
bx_pci_c::mapRead (Bit32u val)
|
||||
{
|
||||
|
@ -383,16 +454,16 @@ bx_pci_c::print_i440fx_state()
|
|||
{
|
||||
int i;
|
||||
|
||||
BX_INFO(( "i440fxConfAddr:0x%08x", BX_PCI_THIS s.i440fx.confAddr ));
|
||||
BX_INFO(( "i440fxConfData:0x%08x", BX_PCI_THIS s.i440fx.confData ));
|
||||
BX_DEBUG(( "i440fxConfAddr:0x%08x", BX_PCI_THIS s.i440fx.confAddr ));
|
||||
BX_DEBUG(( "i440fxConfData:0x%08x", BX_PCI_THIS s.i440fx.confData ));
|
||||
|
||||
#ifdef DUMP_FULL_I440FX
|
||||
for (i=0; i<256; i++) {
|
||||
BX_INFO(( "i440fxArray%02x:0x%02x", i, BX_PCI_THIS s.i440fx.array[i] ));
|
||||
BX_DEBUG(( "i440fxArray%02x:0x%02x", i, BX_PCI_THIS s.i440fx.array[i] ));
|
||||
}
|
||||
#else /* DUMP_FULL_I440FX */
|
||||
for (i=0x59; i<0x60; i++) {
|
||||
BX_INFO(( "i440fxArray%02x:0x%02x", i, BX_PCI_THIS s.i440fx.array[i] ));
|
||||
BX_DEBUG(( "i440fxArray%02x:0x%02x", i, BX_PCI_THIS s.i440fx.array[i] ));
|
||||
}
|
||||
#endif /* DUMP_FULL_I440FX */
|
||||
}
|
||||
|
@ -415,3 +486,32 @@ bx_pci_c::i440fx_fetch_ptr(Bit32u addr)
|
|||
else
|
||||
return (&BX_PCI_THIS devices->mem->vector[addr]);
|
||||
}
|
||||
|
||||
|
||||
Boolean
|
||||
bx_pci_c::register_pci_handlers( void *this_ptr, bx_pci_read_handler_t f1,
|
||||
bx_pci_write_handler_t f2, Bit8u devfunc,
|
||||
const char *name)
|
||||
{
|
||||
unsigned handle;
|
||||
|
||||
/* first check if device/function is available */
|
||||
if (BX_PCI_THIS pci_handler_id[devfunc] == BX_MAX_PCI_DEVICES) {
|
||||
if (BX_PCI_THIS num_pci_handles >= BX_MAX_PCI_DEVICES) {
|
||||
BX_INFO(("too many PCI devices installed."));
|
||||
BX_PANIC((" try increasing BX_MAX_PCI_DEVICES"));
|
||||
return false;
|
||||
}
|
||||
handle = BX_PCI_THIS num_pci_handles++;
|
||||
BX_PCI_THIS pci_handler[handle].read = f1;
|
||||
BX_PCI_THIS pci_handler[handle].write = f2;
|
||||
BX_PCI_THIS pci_handler[handle].this_ptr = this_ptr;
|
||||
BX_PCI_THIS pci_handler_id[devfunc] = handle;
|
||||
BX_INFO(("%s present at device %d, function %d", name, devfunc >> 3,
|
||||
devfunc & 0x07));
|
||||
return true; // device/function mapped successfully
|
||||
}
|
||||
else {
|
||||
return false; // device/function not available, return false.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id: pci.h,v 1.5 2001-11-14 01:39:22 bdenney Exp $
|
||||
// $Id: pci.h,v 1.6 2002-05-30 07:33:48 vruppert Exp $
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001 MandrakeSoft S.A.
|
||||
// Copyright (C) 2002 MandrakeSoft S.A.
|
||||
//
|
||||
// MandrakeSoft S.A.
|
||||
// 43, rue d'Aboukir
|
||||
|
@ -27,6 +27,11 @@
|
|||
|
||||
#if BX_PCI_SUPPORT
|
||||
|
||||
#define BX_MAX_PCI_DEVICES 20
|
||||
|
||||
typedef Bit32u (*bx_pci_read_handler_t)(void *, Bit8u, unsigned);
|
||||
typedef void (*bx_pci_write_handler_t)(void *, Bit8u, Bit32u, unsigned);
|
||||
|
||||
#if BX_USE_PCI_SMF
|
||||
# define BX_PCI_SMF static
|
||||
# define BX_PCI_THIS bx_pci.
|
||||
|
@ -52,6 +57,9 @@ public:
|
|||
~bx_pci_c(void);
|
||||
BX_PCI_SMF void init(bx_devices_c *);
|
||||
BX_PCI_SMF void reset(void);
|
||||
Boolean register_pci_handlers(void *this_ptr, bx_pci_read_handler_t f1,
|
||||
bx_pci_write_handler_t f2, Bit8u devfunc,
|
||||
const char *name);
|
||||
BX_PCI_SMF void print_i440fx_state( );
|
||||
BX_PCI_SMF Bit32u rd_memType (Bit32u addr);
|
||||
BX_PCI_SMF Bit32u wr_memType (Bit32u addr);
|
||||
|
@ -64,11 +72,23 @@ public:
|
|||
private:
|
||||
bx_devices_c *devices;
|
||||
|
||||
Bit8u pci_handler_id[0x100]; // 256 devices/functions
|
||||
struct {
|
||||
bx_pci_read_handler_t read;
|
||||
bx_pci_write_handler_t write;
|
||||
void *this_ptr;
|
||||
} pci_handler[BX_MAX_PCI_DEVICES];
|
||||
unsigned num_pci_handles;
|
||||
|
||||
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
|
||||
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
|
||||
static Bit32u pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len);
|
||||
static void pci_write_handler(void *this_ptr, Bit8u address, Bit32u value, unsigned io_len);
|
||||
#if !BX_USE_PCI_SMF
|
||||
Bit32u read(Bit32u address, unsigned io_len);
|
||||
void write(Bit32u address, Bit32u value, unsigned io_len);
|
||||
Bit32u pci_read(Bit8u address, unsigned io_len);
|
||||
void pci_write(Bit8u address, Bit32u value, unsigned io_len);
|
||||
#endif
|
||||
BX_PCI_SMF Bit32u mapRead (Bit32u val);
|
||||
BX_PCI_SMF Bit32u mapWrite (Bit32u val);
|
||||
|
|
Loading…
Reference in New Issue