1 /////////////////////////////////////////////////////////////////////////
2 // $Id: pci.cc 14299 2021-07-03 08:33:09Z vruppert $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2002-2021 The Bochs Project
6 //
7 // This library is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU Lesser General Public
9 // License as published by the Free Software Foundation; either
10 // version 2 of the License, or (at your option) any later version.
11 //
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // Lesser General Public License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public
18 // License along with this library; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
21 // PCI host bridge support
22 // i430FX - TSC/TDP
23 // i440FX - PMC/DBX
24 // i440BX - Host bridge
25
26 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
27 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
28 // is used to know when we are exporting symbols and when we are importing.
29 #define BX_PLUGGABLE
30
31 #include "iodev.h"
32
33 #if BX_SUPPORT_PCI
34
35 #include "pci.h"
36
37 #define LOG_THIS thePciBridge->
38
39 const char csname[3][20] = {"i430FX TSC", "i440FX PMC", "i440BX Host bridge"};
40
41 bx_pci_bridge_c *thePciBridge = NULL;
42
PLUGIN_ENTRY_FOR_MODULE(pci)43 PLUGIN_ENTRY_FOR_MODULE(pci)
44 {
45 if (mode == PLUGIN_INIT) {
46 thePciBridge = new bx_pci_bridge_c();
47 BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePciBridge, BX_PLUGIN_PCI);
48 } else if (mode == PLUGIN_FINI) {
49 delete thePciBridge;
50 } else if (mode == PLUGIN_PROBE) {
51 return (int)PLUGTYPE_CORE;
52 }
53 return 0; // Success
54 }
55
bx_pci_bridge_c()56 bx_pci_bridge_c::bx_pci_bridge_c()
57 {
58 put("PCI");
59 vbridge = NULL;
60 }
61
~bx_pci_bridge_c()62 bx_pci_bridge_c::~bx_pci_bridge_c()
63 {
64 if (vbridge != NULL) {
65 delete vbridge;
66 }
67 SIM->get_bochs_root()->remove("pci_bridge");
68 BX_DEBUG(("Exit"));
69 }
70
init(void)71 void bx_pci_bridge_c::init(void)
72 {
73 // called once when bochs initializes
74 unsigned i;
75 Bit32u ramsize;
76
77 Bit8u devfunc = BX_PCI_DEVICE(0, 0);
78 BX_PCI_THIS chipset = SIM->get_param_enum(BXPN_PCI_CHIPSET)->get();
79 DEV_register_pci_handlers(this, &devfunc, BX_PLUGIN_PCI, csname[BX_PCI_THIS chipset]);
80
81 // initialize readonly registers
82 if (BX_PCI_THIS chipset == BX_PCI_CHIPSET_I430FX) {
83 init_pci_conf(0x8086, 0x0122, 0x02, 0x060000, 0x00, 0);
84 } else if (BX_PCI_THIS chipset == BX_PCI_CHIPSET_I440BX) {
85 if (DEV_agp_present()) {
86 init_pci_conf(0x8086, 0x7190, 0x02, 0x060000, 0x00, 0);
87 BX_PCI_THIS pci_conf[0x06] = 0x10;
88 BX_PCI_THIS pci_conf[0x10] = 0x08;
89 init_bar_mem(0, 0xf0000000, agp_ap_read_handler, agp_ap_write_handler);
90 BX_PCI_THIS pci_conf[0x34] = 0xa0;
91 BX_PCI_THIS pci_conf[0xa0] = 0x02;
92 BX_PCI_THIS pci_conf[0xa2] = 0x10;
93 BX_PCI_THIS pci_conf[0xa4] = 0x03;
94 BX_PCI_THIS pci_conf[0xa5] = 0x02;
95 BX_PCI_THIS pci_conf[0xa7] = 0x1f;
96 BX_PCI_THIS vbridge = new bx_pci_vbridge_c();
97 BX_PCI_THIS vbridge->init();
98 } else {
99 init_pci_conf(0x8086, 0x7192, 0x02, 0x060000, 0x00, 0);
100 BX_PCI_THIS pci_conf[0x7a] = 0x02;
101 }
102 BX_PCI_THIS pci_conf[0x51] = 0x20;
103 // 'Intel reserved' values
104 BX_PCI_THIS pci_conf[0x71] = 0x1f;
105 BX_PCI_THIS pci_conf[0x94] = 0x04;
106 BX_PCI_THIS pci_conf[0x95] = 0x61;
107 BX_PCI_THIS pci_conf[0x99] = 0x05;
108 BX_PCI_THIS pci_conf[0xc8] = 0x18;
109 BX_PCI_THIS pci_conf[0xc9] = 0x0c;
110 BX_PCI_THIS pci_conf[0xf3] = 0xf8;
111 BX_PCI_THIS pci_conf[0xf8] = 0x20;
112 BX_PCI_THIS pci_conf[0xf9] = 0x0f;
113 } else { // i440FX
114 init_pci_conf(0x8086, 0x1237, 0x00, 0x060000, 0x00, 0);
115 }
116
117 // DRAM module setup
118 for (i = 0; i < 8; i++)
119 BX_PCI_THIS DRBA[i] = 0x0;
120 ramsize = SIM->get_param_num(BXPN_MEM_SIZE)->get();
121 if ((ramsize & 0x07) != 0) {
122 ramsize = (ramsize & ~0x07) + 8;
123 }
124 if (BX_PCI_THIS chipset == BX_PCI_CHIPSET_I430FX) {
125 if (ramsize > 128) ramsize = 128;
126 if (ramsize == 8) {
127 for (i = 0; i < 5; i++) {
128 BX_PCI_THIS DRBA[i] = 0x02;
129 }
130 } else if (ramsize == 16) {
131 BX_PCI_THIS DRBA[0] = 0x02;
132 for (i = 1; i < 5; i++) {
133 BX_PCI_THIS DRBA[i] = 0x04;
134 }
135 } else if (ramsize == 24) {
136 BX_PCI_THIS DRBA[0] = 0x02;
137 BX_PCI_THIS DRBA[1] = 0x04;
138 for (i = 2; i < 5; i++) {
139 BX_PCI_THIS DRBA[i] = 0x06;
140 }
141 } else if (ramsize == 32) {
142 BX_PCI_THIS DRBA[0] = 0x04;
143 for (i = 1; i < 5; i++) {
144 BX_PCI_THIS DRBA[i] = 0x08;
145 }
146 } else if (ramsize <= 48) {
147 BX_PCI_THIS DRBA[0] = 0x04;
148 BX_PCI_THIS DRBA[1] = 0x08;
149 for (i = 2; i < 5; i++) {
150 BX_PCI_THIS DRBA[i] = 0x0c;
151 }
152 } else if (ramsize <= 64) {
153 BX_PCI_THIS DRBA[0] = 0x08;
154 for (i = 1; i < 5; i++) {
155 BX_PCI_THIS DRBA[i] = 0x10;
156 }
157 } else if (ramsize <= 96) {
158 BX_PCI_THIS DRBA[0] = 0x04;
159 BX_PCI_THIS DRBA[1] = 0x08;
160 BX_PCI_THIS DRBA[2] = 0x10;
161 BX_PCI_THIS DRBA[3] = 0x18;
162 BX_PCI_THIS DRBA[4] = 0x18;
163 } else if (ramsize <= 128) {
164 BX_PCI_THIS DRBA[0] = 0x10;
165 for (i = 1; i < 5; i++) {
166 BX_PCI_THIS DRBA[i] = 0x20;
167 }
168 }
169 } else { // i440FX
170 const Bit8u type[3] = {128, 32, 8};
171 if (ramsize > 1024) ramsize = 1024;
172 Bit8u drbval = 0;
173 unsigned row = 0;
174 unsigned ti = 0;
175 while ((ramsize > 0) && (row < 8) && (ti < 3)) {
176 unsigned mc = ramsize / type[ti];
177 ramsize = ramsize % type[ti];
178 for (i = 0; i < mc; i++) {
179 drbval += (type[ti] >> 3);
180 BX_PCI_THIS DRBA[row++] = drbval;
181 if (row == 8) break;
182 }
183 ti++;
184 }
185 while (row < 8) {
186 BX_PCI_THIS DRBA[row++] = drbval;
187 }
188 }
189 for (i = 0; i < 8; i++)
190 BX_PCI_THIS pci_conf[0x60 + i] = BX_PCI_THIS DRBA[i];
191 dram_detect = 0;
192
193 #if BX_DEBUGGER
194 // register device for the 'info device' command (calls debug_dump())
195 bx_dbg_register_debug_info("pci", this);
196 #endif
197 }
198
199 void
reset(unsigned type)200 bx_pci_bridge_c::reset(unsigned type)
201 {
202 unsigned i;
203
204 BX_PCI_THIS pci_conf[0x04] = 0x06;
205 BX_PCI_THIS pci_conf[0x05] = 0x00;
206 BX_PCI_THIS pci_conf[0x07] = 0x02;
207 BX_PCI_THIS pci_conf[0x0d] = 0x00;
208 BX_PCI_THIS pci_conf[0x0f] = 0x00;
209 BX_PCI_THIS pci_conf[0x50] = 0x00;
210 BX_PCI_THIS pci_conf[0x52] = 0x00;
211 BX_PCI_THIS pci_conf[0x53] = 0x80;
212 BX_PCI_THIS pci_conf[0x54] = 0x00;
213 BX_PCI_THIS pci_conf[0x55] = 0x00;
214 BX_PCI_THIS pci_conf[0x56] = 0x00;
215 BX_PCI_THIS pci_conf[0x57] = 0x01;
216 if (BX_PCI_THIS chipset == BX_PCI_CHIPSET_I430FX) {
217 BX_PCI_THIS pci_conf[0x06] = 0x00;
218 BX_PCI_THIS pci_conf[0x58] = 0x00;
219 } else if (BX_PCI_THIS chipset == BX_PCI_CHIPSET_I440BX) {
220 if (BX_PCI_THIS vbridge != NULL) {
221 BX_PCI_THIS vbridge->reset(type);
222 }
223 } else { // i440FX
224 BX_PCI_THIS pci_conf[0x06] = 0x80;
225 BX_PCI_THIS pci_conf[0x51] = 0x01;
226 BX_PCI_THIS pci_conf[0x58] = 0x10;
227 BX_PCI_THIS pci_conf[0xb4] = 0x00;
228 BX_PCI_THIS pci_conf[0xb9] = 0x00;
229 BX_PCI_THIS pci_conf[0xba] = 0x00;
230 BX_PCI_THIS pci_conf[0xbb] = 0x00;
231 BX_PCI_THIS gart_base = 0;
232 }
233 for (i=0x59; i<0x60; i++)
234 BX_PCI_THIS pci_conf[i] = 0x00;
235 for (i = 0; i <= BX_MEM_AREA_F0000; i++) {
236 DEV_mem_set_memory_type(i, 0, 0);
237 DEV_mem_set_memory_type(i, 1, 0);
238 }
239 BX_PCI_THIS pci_conf[0x72] = 0x02;
240 }
241
register_state(void)242 void bx_pci_bridge_c::register_state(void)
243 {
244 bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "pci_bridge", "PCI Bridge State");
245 register_pci_state(list);
246 if (BX_PCI_THIS vbridge != NULL) {
247 BX_PCI_THIS vbridge->register_state();
248 }
249 }
250
after_restore_state(void)251 void bx_pci_bridge_c::after_restore_state(void)
252 {
253 BX_PCI_THIS smram_control(BX_PCI_THIS pci_conf[0x72]);
254 if (BX_PCI_THIS vbridge != NULL) {
255 BX_PCI_THIS vbridge->after_restore_state();
256 }
257 }
258
259 // pci configuration space write callback handler
pci_write_handler(Bit8u address,Bit32u value,unsigned io_len)260 void bx_pci_bridge_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
261 {
262 Bit8u value8, oldval;
263 unsigned area;
264 Bit8u drba_reg, old_dram_detect;
265 bool drba_changed;
266 bool attbase_changed = 0;
267 Bit32u apsize;
268
269 old_dram_detect = BX_PCI_THIS dram_detect;
270 if ((address >= 0x10) && (address < 0x34))
271 return;
272
273 BX_DEBUG_PCI_WRITE(address, value, io_len);
274 for (unsigned i=0; i<io_len; i++) {
275 value8 = (value >> (i*8)) & 0xFF;
276 oldval = BX_PCI_THIS pci_conf[address+i];
277 switch (address+i) {
278 case 0x04:
279 if (BX_PCI_THIS chipset == BX_PCI_CHIPSET_I430FX) {
280 BX_PCI_THIS pci_conf[address+i] = (value8 & 0x02) | 0x04;
281 } else {
282 BX_PCI_THIS pci_conf[address+i] = (value8 & 0x40) | 0x06;
283 }
284 break;
285 case 0x05:
286 if (BX_PCI_THIS chipset != BX_PCI_CHIPSET_I430FX) {
287 BX_PCI_THIS pci_conf[address+i] = (value8 & 0x01);
288 }
289 break;
290 case 0x07:
291 if (BX_PCI_THIS chipset == BX_PCI_CHIPSET_I430FX) {
292 value8 &= 0x30;
293 } else if (BX_PCI_THIS chipset != BX_PCI_CHIPSET_I440BX) {
294 value8 = (BX_PCI_THIS pci_conf[0x07] & ~value8) | 0x02;
295 } else {
296 value8 &= 0xf9;
297 }
298 BX_PCI_THIS pci_conf[address+i] &= ~value8;
299 break;
300 case 0x0d:
301 BX_PCI_THIS pci_conf[address+i] = (value8 & 0xf8);
302 break;
303 case 0x06:
304 case 0x0c:
305 case 0x0f:
306 break;
307 case 0x50:
308 if (BX_PCI_THIS chipset == BX_PCI_CHIPSET_I430FX) {
309 BX_PCI_THIS pci_conf[address+i] = (value8 & 0xef);
310 } else if (BX_PCI_THIS chipset == BX_PCI_CHIPSET_I440BX) {
311 BX_PCI_THIS pci_conf[address+i] = (value8 & 0xec);
312 } else {
313 BX_PCI_THIS pci_conf[address+i] = (value8 & 0x70);
314 }
315 break;
316 case 0x51:
317 if (BX_PCI_THIS chipset != BX_PCI_CHIPSET_I430FX) {
318 BX_PCI_THIS pci_conf[address+i] = (value8 & 0x80) | 0x01;
319 } else if (BX_PCI_THIS chipset == BX_PCI_CHIPSET_I440BX) {
320 BX_PCI_THIS pci_conf[address+i] = (value8 & 0x8f) | 0x20;
321 }
322 break;
323 case 0x59:
324 case 0x5A:
325 case 0x5B:
326 case 0x5C:
327 case 0x5D:
328 case 0x5E:
329 case 0x5F:
330 if (value8 != oldval) {
331 BX_PCI_THIS pci_conf[address+i] = value8;
332 if ((address+i) == 0x59) {
333 area = BX_MEM_AREA_F0000;
334 DEV_mem_set_memory_type(area, 0, (value8 >> 4) & 0x1);
335 DEV_mem_set_memory_type(area, 1, (value8 >> 5) & 0x1);
336 } else {
337 area = ((address+i) - 0x5a) << 1;
338 DEV_mem_set_memory_type(area, 0, (value8 >> 0) & 0x1);
339 DEV_mem_set_memory_type(area, 1, (value8 >> 1) & 0x1);
340 area++;
341 DEV_mem_set_memory_type(area, 0, (value8 >> 4) & 0x1);
342 DEV_mem_set_memory_type(area, 1, (value8 >> 5) & 0x1);
343 }
344 BX_INFO(("%s write to PAM register %x (TLB Flush)", csname[BX_PCI_THIS chipset], address+i));
345 bx_pc_system.MemoryMappingChanged();
346 }
347 break;
348 case 0x60:
349 case 0x61:
350 case 0x62:
351 case 0x63:
352 case 0x64:
353 case 0x65:
354 case 0x66:
355 case 0x67:
356 BX_PCI_THIS pci_conf[address+i] = value8;
357 drba_reg = (address + i) & 0x07;
358 drba_changed = (BX_PCI_THIS pci_conf[0x60 + drba_reg] != BX_PCI_THIS DRBA[drba_reg]);
359 if (drba_changed) {
360 BX_PCI_THIS dram_detect |= (1 << drba_reg);
361 } else if (!drba_changed && dram_detect) {
362 BX_PCI_THIS dram_detect &= ~(1 << drba_reg);
363 }
364 break;
365 case 0x72:
366 smram_control(value8); // SMRAM control register
367 break;
368 case 0x7a:
369 BX_PCI_THIS pci_conf[address+i] &= 0x0a;
370 BX_PCI_THIS pci_conf[address+i] |= (value8 & 0xf5);
371 break;
372 case 0xb4:
373 if (BX_PCI_THIS chipset == BX_PCI_CHIPSET_I440BX) {
374 BX_PCI_THIS pci_conf[address+i] = value8 & 0x3f;
375 switch (BX_PCI_THIS pci_conf[0xb4]) {
376 case 0x00:
377 apsize = (1 << 28);
378 break;
379 case 0x20:
380 apsize = (1 << 27);
381 break;
382 case 0x30:
383 apsize = (1 << 26);
384 break;
385 case 0x38:
386 apsize = (1 << 25);
387 break;
388 case 0x3c:
389 apsize = (1 << 24);
390 break;
391 case 0x3e:
392 apsize = (1 << 23);
393 break;
394 case 0x3f:
395 apsize = (1 << 22);
396 break;
397 default:
398 BX_ERROR(("Invalid AGP aperture size mask"));
399 apsize = 0;
400 }
401 BX_INFO(("AGP aperture size set to %d MB", apsize >> 20));
402 pci_bar[0].size = apsize;
403 }
404 break;
405 case 0xb8:
406 break;
407 case 0xb9:
408 value8 &= 0xf0;
409 case 0xba:
410 case 0xbb:
411 if ((BX_PCI_THIS chipset == BX_PCI_CHIPSET_I440BX) &&
412 (value8 != oldval)) {
413 BX_PCI_THIS pci_conf[address+i] = value8;
414 attbase_changed |= 1;
415 }
416 break;
417 case 0xf0:
418 if (BX_PCI_THIS chipset == BX_PCI_CHIPSET_I440BX) {
419 BX_PCI_THIS pci_conf[address+i] = value8 & 0xc0;
420 }
421 break;
422 default:
423 BX_PCI_THIS pci_conf[address+i] = value8;
424 BX_DEBUG(("%s write register 0x%02x value 0x%02x", csname[BX_PCI_THIS chipset], address+i, value8));
425 }
426 }
427 if ((BX_PCI_THIS dram_detect > 0) && (old_dram_detect == 0)) {
428 // TODO
429 BX_ERROR(("FIXME: DRAM module detection"));
430 } else if ((BX_PCI_THIS dram_detect == 0) && (old_dram_detect > 0)) {
431 // TODO
432 BX_INFO(("normal memory access mode"));
433 }
434 if (attbase_changed) {
435 BX_PCI_THIS gart_base = ((BX_PCI_THIS pci_conf[0xbb] << 24) |
436 (BX_PCI_THIS pci_conf[0xba] << 16) |
437 (BX_PCI_THIS pci_conf[0xb9] << 8));
438 BX_INFO(("New GART base address = 0x%08x", BX_PCI_THIS gart_base));
439 }
440 }
441
agp_ap_read_handler(bx_phy_address addr,unsigned len,void * data,void * param)442 bool bx_pci_bridge_c::agp_ap_read_handler(bx_phy_address addr, unsigned len,
443 void *data, void *param)
444 {
445 bx_pci_bridge_c *class_ptr = (bx_pci_bridge_c*)param;
446 Bit32u value = class_ptr->agp_aperture_read(addr, len, 0);
447 switch (len) {
448 case 1:
449 value &= 0xFF;
450 *((Bit8u *) data) = (Bit8u) value;
451 break;
452 case 2:
453 value &= 0xFFFF;
454 *((Bit16u *) data) = (Bit16u) value;
455 break;
456 case 4:
457 *((Bit32u *) data) = value;
458 break;
459 }
460 return 1;
461 }
462
agp_aperture_read(bx_phy_address addr,unsigned len,bool agp)463 Bit32u bx_pci_bridge_c::agp_aperture_read(bx_phy_address addr, unsigned len,
464 bool agp)
465 {
466 if (BX_PCI_THIS pci_conf[0x51] & 0x02) {
467 Bit32u offset = (Bit32u)(addr - pci_bar[0].addr);
468 Bit32u gart_index = (Bit32u)(offset >> 12);
469 Bit32u page_offset = (Bit32u)(offset & 0xfff);
470 Bit32u gart_addr = BX_PCI_THIS gart_base + (gart_index << 2);
471 Bit32u page_addr;
472 DEV_MEM_READ_PHYSICAL(gart_addr, 4, (Bit8u*)&page_addr);
473 BX_INFO(("TODO: AGP aperture read: page address = 0x%08x / offset = 0x%04x",
474 page_addr, (Bit16u)page_offset));
475 // TODO
476 }
477 return 0;
478 }
479
agp_ap_write_handler(bx_phy_address addr,unsigned len,void * data,void * param)480 bool bx_pci_bridge_c::agp_ap_write_handler(bx_phy_address addr, unsigned len,
481 void *data, void *param)
482 {
483 bx_pci_bridge_c *class_ptr = (bx_pci_bridge_c*)param;
484 Bit32u value = *(Bit32u*)data;
485 class_ptr->agp_aperture_write(addr, value, len, 0);
486 return 1;
487 }
488
agp_aperture_write(bx_phy_address addr,Bit32u value,unsigned len,bool agp)489 void bx_pci_bridge_c::agp_aperture_write(bx_phy_address addr, Bit32u value,
490 unsigned len, bool agp)
491 {
492 if (BX_PCI_THIS pci_conf[0x51] & 0x02) {
493 Bit32u offset = (Bit32u)(addr - pci_bar[0].addr);
494 Bit32u gart_index = (Bit32u)(offset >> 12);
495 Bit32u page_offset = (Bit32u)(offset & 0xfff);
496 Bit32u gart_addr = BX_PCI_THIS gart_base + (gart_index << 2);
497 Bit32u page_addr;
498 DEV_MEM_READ_PHYSICAL(gart_addr, 4, (Bit8u*)&page_addr);
499 BX_INFO(("TODO: AGP aperture write: page address = 0x%08x / offset = 0x%04x",
500 page_addr, (Bit16u)page_offset));
501 // TODO
502 }
503 }
504
smram_control(Bit8u value8)505 void bx_pci_bridge_c::smram_control(Bit8u value8)
506 {
507 //
508 // From i440FX chipset manual:
509 //
510 // [7:7] Reserved.
511 // [6:6] SMM Space Open (DOPEN), when DOPEN=1 and DLCK=0, SMM space DRAM
512 // became visible even CPU not indicte SMM mode access. This is
513 // indended to help BIOS to initialize SMM space.
514 // [5:5] SMM Space Closed (DCLS), when DCLS=1, SMM space is not accessible
515 // for data references, even if CPU indicates SMM mode access. Code
516 // references may still access SMM space DRAM.
517 // [4:4] SMM Space Locked (DLCK), when DLCK=1, DOPEN is set to 0 and
518 // both DLCK and DOPEN became R/O. DLCK can only be cleared by
519 // a power-on reset.
520 // [3:3] SMRAM Enable (SMRAME)
521 // [2:0] SMM space base segment, program the location of SMM space
522 // reserved.
523 //
524
525 // SMRAM space access cycles:
526
527 // | SMRAME | DLCK | DCLS | DOPEN | CPU_SMM | | Code | Data |
528 // ------------------------------------------ ---------------
529 // | 0 | X | X | X | X | -> | PCI | PCI |
530 // | 1 | 0 | X | 0 | 0 | -> | PCI | PCI |
531 // | 1 | 0 | 0 | 0 | 1 | -> | DRAM | DRAM |
532 // | 1 | 0 | 0 | 1 | X | -> | DRAM | DRAM |
533 // | 1 | 1 | 0 | X | 1 | -> | DRAM | DRAM |
534 // | 1 | 0 | 1 | 0 | 1 | -> | DRAM | PCI |
535 // | 1 | 0 | 1 | 1 | X | -> | ---- | ---- |
536 // | 1 | 1 | X | X | 0 | -> | PCI | PCI |
537 // | 1 | 1 | 1 | X | 1 | -> | DRAM | PCI |
538 // ------------------------------------------ ---------------
539
540 value8 = (value8 & 0x78) | 0x2; // ignore reserved bits
541
542 if (BX_PCI_THIS pci_conf[0x72] & 0x10)
543 {
544 value8 &= 0xbf; // set DOPEN=0, DLCK=1
545 value8 |= 0x10;
546 }
547
548 if ((value8 & 0x08) == 0) {
549 bx_devices.mem->disable_smram();
550 }
551 else {
552 bool DOPEN = (value8 & 0x40) > 0, DCLS = (value8 & 0x20) > 0;
553 if(DOPEN && DCLS) BX_PANIC(("SMRAM control: DOPEN not mutually exclusive with DCLS !"));
554 bx_devices.mem->enable_smram(DOPEN, DCLS);
555 }
556
557 BX_INFO(("setting SMRAM control register to 0x%02x", value8));
558 BX_PCI_THIS pci_conf[0x72] = value8;
559 }
560
561 #if BX_DEBUGGER
debug_dump(int argc,char ** argv)562 void bx_pci_bridge_c::debug_dump(int argc, char **argv)
563 {
564 int arg, i, j, r;
565
566 if (BX_PCI_THIS chipset == BX_PCI_CHIPSET_I430FX) {
567 dbg_printf("i430FX TSC/TDP");
568 } else if (BX_PCI_THIS chipset == BX_PCI_CHIPSET_I440BX) {
569 dbg_printf("i440BX Host bridge");
570 } else {
571 dbg_printf("i440FX PMC/DBX");
572 }
573 dbg_printf("\n\nconfAddr = 0x%08x\n\n", DEV_pci_get_confAddr());
574
575 if (argc == 0) {
576 for (i = 0x59; i < 0x60; i++) {
577 dbg_printf("PAM reg 0x%02x = 0x%02x\n", i, BX_PCI_THIS pci_conf[i]);
578 }
579 dbg_printf("SMRAM control = 0x%02x\n", BX_PCI_THIS pci_conf[0x72]);
580 dbg_printf("\nSupported options:\n");
581 dbg_printf("info device 'pci' 'dump=full' - show PCI config space\n");
582 } else {
583 for (arg = 0; arg < argc; arg++) {
584 if (!strcmp(argv[arg], "dump=full")) {
585 dbg_printf("\nPCI config space\n\n");
586 r = 0;
587 for (i=0; i<16; i++) {
588 dbg_printf("%04x ", r);
589 for (j=0; j<16; j++) {
590 dbg_printf(" %02x", BX_PCI_THIS pci_conf[r++]);
591 }
592 dbg_printf("\n");
593 }
594 } else {
595 dbg_printf("\nUnknown option: '%s'\n", argv[arg]);
596 }
597 }
598 }
599 }
600 #endif
601
602 // i440BX PCI-to-AGP bridge
603
604 #undef LOG_THIS
605 #define LOG_THIS
606
bx_pci_vbridge_c()607 bx_pci_vbridge_c::bx_pci_vbridge_c()
608 {
609 put("PCIAGP");
610 }
611
~bx_pci_vbridge_c()612 bx_pci_vbridge_c::~bx_pci_vbridge_c()
613 {
614 SIM->get_bochs_root()->remove("pci_vbridge");
615 BX_DEBUG(("Exit"));
616 }
617
init(void)618 void bx_pci_vbridge_c::init(void)
619 {
620 Bit8u devfunc = BX_PCI_DEVICE(1, 0);
621 DEV_register_pci_handlers(this, &devfunc, BX_PLUGIN_PCI, "i440BX PCI-to-AGP bridge");
622 init_pci_conf(0x8086, 0x7191, 0x02, 0x060400, 0x01, 0);
623 pci_conf[0x06] = 0x20;
624 pci_conf[0x07] = 0x02;
625 pci_conf[0x1e] = 0xa0;
626 }
627
reset(unsigned type)628 void bx_pci_vbridge_c::reset(unsigned type)
629 {
630 pci_conf[0x04] = 0x00;
631 pci_conf[0x05] = 0x00;
632 pci_conf[0x1c] = 0xf0;
633 pci_conf[0x1f] = 0x02;
634 pci_conf[0x20] = 0xf0;
635 pci_conf[0x21] = 0xff;
636 pci_conf[0x22] = 0x00;
637 pci_conf[0x23] = 0x00;
638 pci_conf[0x24] = 0xf0;
639 pci_conf[0x25] = 0xff;
640 pci_conf[0x26] = 0x00;
641 pci_conf[0x27] = 0x00;
642 pci_conf[0x3e] = 0x80;
643 }
644
register_state(void)645 void bx_pci_vbridge_c::register_state(void)
646 {
647 bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "pci_vbridge", "PCI/AGP Bridge State");
648 register_pci_state(list);
649 }
650
after_restore_state(void)651 void bx_pci_vbridge_c::after_restore_state(void)
652 {
653 // TODO
654 }
655
656 // pci configuration space write callback handler
pci_write_handler(Bit8u address,Bit32u value,unsigned io_len)657 void bx_pci_vbridge_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
658 {
659 BX_DEBUG_PCI_WRITE(address, value, io_len);
660
661 for (unsigned i=0; i<io_len; i++) {
662 Bit8u value8 = (value >> (i*8)) & 0xff;
663 Bit8u oldval = pci_conf[address+i];
664 switch (address+i) {
665 case 0x04: // PCICMD1
666 value8 &= 0x3f;
667 break;
668 case 0x05:
669 value8 &= 0x01;
670 break;
671 case 0x0d: // MLT1
672 case 0x1b: // SMLT
673 value8 &= 0xf8;
674 break;
675 case 0x1c: // IOBASE
676 case 0x1d: // IOLIMIT
677 case 0x20: // MBASE lo
678 case 0x22: // MLIMIT lo
679 case 0x24: // PMBASE lo
680 case 0x26: // PMLIMIT lo
681 value8 &= 0xf0;
682 break;
683 case 0x1f: // SSTS hi
684 value8 = (pci_conf[0x1f] & ~value8) | 0x02;
685 break;
686 case 0x3e: // BCTRL
687 value8 = (value8 & 0xc1) | 0x80;
688 break;
689 case 0x19: // SBUSN - all bits r/w
690 case 0x1a: // SUBUSN
691 case 0x21: // MBASE hi
692 case 0x23: // MLIMIT hi
693 case 0x25: // PMBASE hi
694 case 0x27: // PMLIMIT hi
695 break;
696 case 0x06: // PCISTS1 - all bits r/o
697 case 0x07:
698 case 0x18: // PBUSN
699 case 0x1e: // SSTS lo
700 default:
701 value8 = oldval;
702 }
703 pci_conf[address+i] = value8;
704 }
705 }
706 #endif /* BX_SUPPORT_PCI */
707