1 class PCIDevice
: public Device
4 void rw_config(uint8_t addr
, unsigned len
, uint32_t *data
, bool read
);
13 uint8_t subclass_code
;
19 Array
<uint32_t, 6> bar
;
21 uint16_t subvendor_id
;
22 uint16_t subdevice_id
;
31 void PCIDevice::config_rw(uint8_t addr
, unsigned len
, uint32_t *data
, bool read
)
33 RegisterIO
reg(addr
, len
, data
, read
);
35 /* These are required to be implemented */
36 reg
.io(&this->vendor_id
, 0x00, READONLY
);
37 reg
.io(&this->device_id
, 0x02, READONLY
);
38 reg
.io(&this->command
, 0x04);
39 reg
.io(&this->status
, 0x06);
40 reg
.io(&this->rid
, 0x08, READONLY
);
41 reg
.io(&this->prog_if
, 0x09, READONLY
);
42 reg
.io(&this->subclass_code
, 0x0A, READONLY
);
43 reg
.io(&this->class_code
, 0x0B, READONLY
);
44 reg
.io(&this->headt
, 0x0E);
55 * The i440fx is the motherboard chipset that was popular in the Pentium Pro
56 * era. At this point in time, the chipset included both the Northbridge
57 * (Memory Controller) and Southbridge (IO devices) functionality.
59 * The i440fx has a PCI 2.1 compatible bus and a PCI-to-ISA bridge. All port
60 * I/O and main memory access goes through the i440fx with the exception of
61 * access to the local APIC which is part of the processor.
63 * The main interface to the i440fx is through the PCI interface. The memory
64 * controller is accessable as PCI device 0:0.0 even though it's technically
65 * not a PCI device as the transactions for the device don't go over the PCI
68 class I440FX
: public Device
72 * Port I/O entry points. It's expected that all PIO is sent through this
75 void pio_write(uint16_t addr
, uint32_t data
, unsigned len
);
76 uint32_t pio_read(uint16_t addr
, unsigned len
);
79 * Memory entry points. See mem_intercepts for usage.
81 void mem_write(uint64_t addr
, uint64_t data
, unsigned len
);
82 uint64_t mem_read(uint64_t addr
, unsigned len
);
85 * Memory intercept API. For performance reasons, instead of requiring all
86 * memory accesses go through mem_write/mem_read, we provide a list of
87 * regions that we care to go through our interface.
89 const std::vector
<MemoryRegion
> &get_mem_intercepts(void) const;
91 void set_mem_change_notifier(std::function
<void (void)> fn
);
94 void confdata_write(uint32_t data
, unsigned len
);
95 uint32_t confdata_read(unsigned len
);
97 void pmc_write(uint8_t regnum
, uint32_t data
, unsigned len
);
98 uint32_t pmc_read(uint8_t regnum
, unsigned len
);
100 std::vector
<MemoryRegion
> mem_intercepts
;
101 std::function
<void (void)> fn
;
111 uint8_t subclass_code
;
123 Array
<uint8_t, 7> pam
;
124 Array
<uint8_t, 8> drb
;
134 void I440FX::reset(void)
137 this->confadd
= 0x00;
142 void I440FX::update_ram_shadowing(void)
146 void I440FX::pmc_rw(uint8_t regnum
, unsigned len
, uint32_t *data
, bool read
)
148 RegisterIO
reg(regnum
, len
, data
, read
);
150 reg
.io(&this->vendor_id
, 0x00, READONLY
);
151 reg
.io(&this->device_id
, 0x02, READONLY
);
152 reg
.io(&this->command
, 0x04, 0, 0x029F);
153 reg
.io(&this->status
, 0x06, WRITECLEAR
, 0x380);
154 reg
.io(&this->rid
, 0x08, READ_ONLY
);
155 reg
.io(&this->prog_if
, 0x09, READONLY
);
156 reg
.io(&this->subclass_code
, 0x0A, READONLY
);
157 reg
.io(&this->class_code
, 0x0B, READONLY
);
158 reg
.io(&this->mlt
, 0x0D);
159 reg
.io(&this->headt
, 0x0E);
160 reg
.io(&this->bist
, 0x0F);
162 reg
.io(&this->pmccfg
, 0x50, READWRITE
, 0x4304);
163 reg
.io(&this->deturbo
, 0x52);
164 reg
.io(&this->dbc
, 0x53);
165 reg
.io(&this->axc
, 0x54);
166 reg
.io(&this->dramr
, 0x55);
167 reg
.io(&this->dramc
, 0x57);
168 reg
.io(&this->dramt
, 0x58);
169 if (reg
.io(&this->pam
, 0x59)) {
170 this->update_ram_shadowing();
172 reg
.io(&this->drb
, 0x60);
173 reg
.io(&this->fdhc
, 0x68);
174 reg
.io(&this->mtt
, 0x70);
175 reg
.io(&this->clt
, 0x71);
176 if (reg
.io(&this->smram
, 0x72)) {
177 this->update_ram_shadowing();
179 reg
.io(&this->errcmd
, 0x90);
180 reg
.io(&this->errsts
, 0x91, WRITECLEAR
);
181 reg
.io(&this->trc
, 0x93, WRITECLEAR
);
184 void I440FX::confdata_write(uint32_t data
, unsigned len
)
186 uint8_t bus
= (data
>> 16) & 0xFF;
187 uint8_t devfn
= (data
>> 8) & 0xFF;
188 uint8_t regnum
= data
& 0xFE;
190 if (bus
== 0 && devfn
== 0) {
191 this->pmc_rw(regnum
, len
, data
, false);
194 PCIDevice
*dev
= this->find_dev(bus
, devfn
);
196 dev
->config_write(regnum
, data
, len
);
201 uint32_t I440FX::confdata_read(unsigned len
)
203 if (bus
== 0 && devfn
== 0) {
204 return this->pmc_rw(regnum
, len
, data
, true);
206 PCIDevice
*dev
= this->find_dev(bus
, devfn
);
208 return dev
->config_read(regnum
, data
, len
);
215 void I440FX::pio_write(uint16_t addr
, uint32_t data
, unsigned len
)
217 /* Only accesses as a dword are intercepted */
218 if (addr
== 0x0CF8 && len
== 4) {
219 this->confadd
= data
;
223 if (addr
== 0x0CFC && (this->confadd
& CONFADD_CONE
)) {
224 this->confdata_write(data
, len
);
228 /* FIXME search for any PCI device that claims this PIO port */
231 uint32_t I440FX::pio_read(uint16_t addr
, unsigned len
)
233 /* Only accesses as a dword are intercepted */
234 if (addr
== 0x0CF8 && len
== 4) {
235 return this->condadd
;
238 if (addr
== 0x0CFC && (this->confadd
& CONFADD_CONE
)) {
239 return this->confdata_read(len
);
242 /* FIXME search for a PCI device that claims this port */