- compilation fixes for MSVC toolkit 2003
[bochs-mirror.git] / iodev / ioapic.cc
blobfb6ab980a7e9bb73d80f447d79b7d42370320c0d
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: ioapic.cc,v 1.37 2008/04/29 22:14:23 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2002 MandrakeSoft S.A.
6 //
7 // MandrakeSoft S.A.
8 // 43, rue d'Aboukir
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "bochs.h"
28 #include "cpu/apic.h"
29 #include "iodev.h"
31 #if BX_SUPPORT_APIC
33 class bx_ioapic_c bx_ioapic;
34 #define LOG_THIS bx_ioapic.
36 static bx_bool ioapic_read(bx_phy_address a20addr, unsigned len, void *data, void *param)
38 bx_ioapic.read(a20addr, data, len);
39 return 1;
42 static bx_bool ioapic_write(bx_phy_address a20addr, unsigned len, void *data, void *param)
44 if (len != 4) {
45 BX_PANIC (("I/O apic write with len=%ld (should be 4)", len));
47 bx_ioapic.write(a20addr, (Bit32u*) data, len);
48 return 1;
51 void bx_io_redirect_entry_t::sprintf_self(char *buf)
53 sprintf(buf, "dest=%02x, masked=%d, trig_mode=%d, remote_irr=%d, polarity=%d, delivery_status=%d, dest_mode=%d, delivery_mode=%d, vector=%02x",
54 (unsigned) destination(),
55 (unsigned) is_masked(),
56 (unsigned) trigger_mode(),
57 (unsigned) remote_irr(),
58 (unsigned) pin_polarity(),
59 (unsigned) delivery_status(),
60 (unsigned) destination_mode(),
61 (unsigned) delivery_mode(),
62 (unsigned) vector());
65 void bx_io_redirect_entry_t::register_state(bx_param_c *parent)
67 BXRS_HEX_PARAM_SIMPLE(parent, lo);
68 BXRS_HEX_PARAM_SIMPLE(parent, hi);
71 #define BX_IOAPIC_BASE_ADDR (0xfec00000)
73 bx_ioapic_c::bx_ioapic_c()
74 : bx_generic_apic_c(BX_IOAPIC_BASE_ADDR)
76 put("IOAP");
77 settype(IOAPICLOG);
80 bx_ioapic_c::~bx_ioapic_c() {}
82 #define BX_IOAPIC_DEFAULT_ID (BX_SMP_PROCESSORS)
84 void bx_ioapic_c::init(void)
86 bx_generic_apic_c::init();
87 BX_INFO(("initializing I/O APIC"));
88 base_addr = BX_IOAPIC_BASE_ADDR;
89 set_id(BX_IOAPIC_DEFAULT_ID);
90 ioregsel = 0;
91 DEV_register_memory_handlers(&bx_ioapic,
92 ioapic_read, ioapic_write, base_addr, base_addr + 0xfff);
93 // all interrupts masked
94 for (int i=0; i<BX_IOAPIC_NUM_PINS; i++) {
95 ioredtbl[i].set_lo_part(0x00010000);
96 ioredtbl[i].set_hi_part(0x00000000);
98 intin = 0;
99 irr = 0;
102 void bx_ioapic_c::read_aligned(bx_phy_address address, Bit32u *data)
104 BX_DEBUG(("IOAPIC: read aligned addr=%08x", address));
105 address &= 0xff;
106 if (address == 0x00) {
107 // select register
108 *data = ioregsel;
109 return;
110 } else {
111 if (address != 0x10)
112 BX_PANIC(("IOAPIC: read from unsupported address"));
114 // only reached when reading data register
115 switch (ioregsel) {
116 case 0x00: // APIC ID, note this is 4bits, the upper 4 are reserved
117 *data = ((id & APIC_ID_MASK) << 24);
118 return;
119 case 0x01: // version
120 *data = BX_IOAPIC_VERSION_ID;
121 return;
122 case 0x02:
123 BX_INFO(("IOAPIC: arbitration ID unsupported, returned 0"));
124 *data = 0;
125 return;
126 default:
127 int index = (ioregsel - 0x10) >> 1;
128 if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
129 bx_io_redirect_entry_t *entry = ioredtbl + index;
130 *data = (ioregsel&1) ? entry->get_hi_part() : entry->get_lo_part();
131 return;
133 BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
137 void bx_ioapic_c::write_aligned(bx_phy_address address, Bit32u *value)
139 BX_DEBUG(("IOAPIC: write aligned addr=%08x, data=%08x", address, *value));
140 address &= 0xff;
141 if (address == 0x00) {
142 ioregsel = *value;
143 return;
144 } else {
145 if (address != 0x10)
146 BX_PANIC(("IOAPIC: write to unsupported address"));
148 // only reached when writing data register
149 switch (ioregsel) {
150 case 0x00: // set APIC ID
152 Bit8u newid = (*value >> 24) & APIC_ID_MASK;
153 BX_INFO(("IOAPIC: setting id to 0x%x", newid));
154 set_id (newid);
155 return;
157 case 0x01: // version
158 case 0x02: // arbitration id
159 BX_INFO(("IOAPIC: could not write, IOREGSEL=0x%02x", ioregsel));
160 return;
161 default:
162 int index = (ioregsel - 0x10) >> 1;
163 if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
164 bx_io_redirect_entry_t *entry = ioredtbl + index;
165 if (ioregsel&1)
166 entry->set_hi_part(*value);
167 else
168 entry->set_lo_part(*value);
169 char buf[1024];
170 entry->sprintf_self(buf);
171 BX_DEBUG(("IOAPIC: now entry[%d] is %s", index, buf));
172 service_ioapic();
173 return;
175 BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
179 void bx_ioapic_c::set_irq_level(Bit8u int_in, bx_bool level)
181 BX_DEBUG(("set_irq_level(): INTIN%d: level=%d", int_in, level));
182 if (int_in < BX_IOAPIC_NUM_PINS) {
183 Bit32u bit = 1<<int_in;
184 if ((level<<int_in) != (intin & bit)) {
185 bx_io_redirect_entry_t *entry = ioredtbl + int_in;
186 if (entry->trigger_mode()) {
187 // level triggered
188 if (level) {
189 intin |= bit;
190 irr |= bit;
191 service_ioapic();
192 } else {
193 intin &= ~bit;
194 irr &= ~bit;
196 } else {
197 // edge triggered
198 if (level) {
199 intin |= bit;
200 irr |= bit;
201 service_ioapic();
202 } else {
203 intin &= ~bit;
210 void bx_ioapic_c::receive_eoi(Bit8u vector)
212 BX_DEBUG(("IOAPIC: received EOI for vector %d", vector));
215 void bx_ioapic_c::service_ioapic()
217 static unsigned int stuck = 0;
218 Bit8u vector = 0;
219 // look in IRR and deliver any interrupts that are not masked.
220 BX_DEBUG(("IOAPIC: servicing"));
221 for (unsigned bit=0; bit < BX_IOAPIC_NUM_PINS; bit++) {
222 Bit32u mask = 1<<bit;
223 if (irr & mask) {
224 bx_io_redirect_entry_t *entry = ioredtbl + bit;
225 if (! entry->is_masked()) {
226 // clear irr bit and deliver
227 if (entry->delivery_mode() == 7) {
228 vector = DEV_pic_iac();
229 } else {
230 vector = entry->vector();
232 bx_bool done = apic_bus_deliver_interrupt(vector, entry->destination(), entry->delivery_mode(), entry->destination_mode(), entry->pin_polarity(), entry->trigger_mode());
233 if (done) {
234 if (! entry->trigger_mode())
235 irr &= ~mask;
236 entry->clear_delivery_status();
237 stuck = 0;
238 } else {
239 entry->set_delivery_status();
240 stuck++;
241 if (stuck > 5)
242 BX_INFO(("vector %#x stuck?", vector));
245 else {
246 BX_DEBUG(("service_ioapic(): INTIN%d is masked", bit));
252 void bx_ioapic_c::register_state(void)
254 bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "ioapic", "IOAPIC State", 4);
255 BXRS_HEX_PARAM_SIMPLE(list, ioregsel);
256 BXRS_HEX_PARAM_SIMPLE(list, intin);
257 BXRS_HEX_PARAM_SIMPLE(list, irr);
259 bx_list_c *table = new bx_list_c(list, "ioredtbl", BX_IOAPIC_NUM_PINS);
260 for (unsigned i=0; i<BX_IOAPIC_NUM_PINS; i++) {
261 char name[6];
262 sprintf(name, "0x%02x", i);
263 bx_list_c *entry = new bx_list_c(table, name, 2);
264 ioredtbl[i].register_state(entry);
268 #endif /* if BX_SUPPORT_APIC */