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