Add i8042 back
[qemupp.git] / pci / pcidevice.hpp
blob727b5d56ba5295a26b580766498210de27c1eb65
1 class PCIDevice : public Device
3 public:
4 void rw_config(uint8_t addr, unsigned len, uint32_t *data, bool read);
6 protected:
7 uint16_t vendor_id;
8 uint16_t device_id;
9 uint16_t command;
10 uint16_t status;
11 uint8_t rid;
12 uint8_t prog_if;
13 uint8_t subclass_code;
14 uint8_t class_code;
15 uint8_t cls;
16 uint8_t mlt;
17 uint8_t headt;
18 uint8_t bist;
19 Array<uint32_t, 6> bar;
20 uint32_t ccp;
21 uint16_t subvendor_id;
22 uint16_t subdevice_id;
23 uint32_t rom_bar;
24 uint8_t cap;
25 uint8_t int_line;
26 uint8_t int_pin;
27 uint8_t min_gnt;
28 uint8_t max_lat;
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);
48 struct MemoryRegion
50 uint64_t start;
51 uint64_t size;
54 /**
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
66 * bus.
68 class I440FX : public Device
70 public:
71 /**
72 * Port I/O entry points. It's expected that all PIO is sent through this
73 * interface.
75 void pio_write(uint16_t addr, uint32_t data, unsigned len);
76 uint32_t pio_read(uint16_t addr, unsigned len);
78 /**
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);
84 /**
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);
93 private:
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;
103 uint32_t confadd;
105 uint16_t vendor_id;
106 uint16_t device_id;
107 uint16_t command;
108 uint16_t status;
109 uint8_t rid;
110 uint8_t prog_if;
111 uint8_t subclass_code;
112 uint8_t class_code;
113 uint8_t mlt;
114 uint8_t headt;
115 uint8_t bist;
116 uint16_t pmccfg;
117 uint8_t deturbo;
118 uint8_t dbc;
119 uint8_t axc;
120 uint16_t dramr;
121 uint8_t dramc;
122 uint8_t dramt;
123 Array<uint8_t, 7> pam;
124 Array<uint8_t, 8> drb;
125 uint8_t fdhc;
126 uint8_t mtt;
127 uint8_t clt;
128 uint8_t smram;
129 uint8_t errcmd;
130 uint8_t errsts;
131 uint8_t trc;
134 void I440FX::reset(void)
136 /* FIXME */
137 this->confadd = 0x00;
138 this->clt = 0x10;
139 this->sram = 0x02;
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);
192 return;
193 } else {
194 PCIDevice *dev = this->find_dev(bus, devfn);
195 if (dev) {
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);
205 } else {
206 PCIDevice *dev = this->find_dev(bus, devfn);
207 if (dev) {
208 return dev->config_read(regnum, data, len);
212 return 0x00;
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;
220 return;
223 if (addr == 0x0CFC && (this->confadd & CONFADD_CONE)) {
224 this->confdata_write(data, len);
225 return;
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 */
244 return 0xFFFFFFFF;