1 /////////////////////////////////////////////////////////////////////////
2 // $Id: unmapped.cc 14241 2021-05-11 14:42:31Z vruppert $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2001-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 /////////////////////////////////////////////////////////////////////////
22
23 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
24 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
25 // is used to know when we are exporting symbols and when we are importing.
26 #define BX_PLUGGABLE
27 #include "iodev.h"
28 #include "unmapped.h"
29
30 #define LOG_THIS theUnmappedDevice->
31
32 bx_unmapped_c *theUnmappedDevice = NULL;
33
PLUGIN_ENTRY_FOR_MODULE(unmapped)34 PLUGIN_ENTRY_FOR_MODULE(unmapped)
35 {
36 if (mode == PLUGIN_INIT) {
37 theUnmappedDevice = new bx_unmapped_c();
38 BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theUnmappedDevice, BX_PLUGIN_UNMAPPED);
39 } else if (mode == PLUGIN_FINI) {
40 delete theUnmappedDevice;
41 } else if (mode == PLUGIN_PROBE) {
42 return (int)PLUGTYPE_OPTIONAL;
43 }
44 return(0); // Success
45 }
46
bx_unmapped_c(void)47 bx_unmapped_c::bx_unmapped_c(void)
48 {
49 put("unmapped", "UNMAP");
50 }
51
~bx_unmapped_c(void)52 bx_unmapped_c::~bx_unmapped_c(void)
53 {
54 BX_DEBUG(("Exit"));
55 }
56
init(void)57 void bx_unmapped_c::init(void)
58 {
59 DEV_register_default_ioread_handler(this, read_handler, "Unmapped", 7);
60 DEV_register_default_iowrite_handler(this, write_handler, "Unmapped", 7);
61
62 s.port80 = 0x00;
63 s.port8e = 0x00;
64 s.shutdown = 0;
65 s.port_e9_hack = SIM->get_param_bool(BXPN_PORT_E9_HACK)->get();
66 SIM->get_param_num(BXPN_PORT_E9_HACK)->set_handler(param_handler);
67 }
68
69 // static IO port read callback handler
70 // redirects to non-static class handler to avoid virtual functions
read_handler(void * this_ptr,Bit32u address,unsigned io_len)71 Bit32u bx_unmapped_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
72 {
73 #if !BX_USE_UM_SMF
74 bx_unmapped_c *class_ptr = (bx_unmapped_c *) this_ptr;
75 return class_ptr->read(address, io_len);
76 }
77
read(Bit32u address,unsigned io_len)78 Bit32u bx_unmapped_c::read(Bit32u address, unsigned io_len)
79 {
80 #else
81 UNUSED(this_ptr);
82 #endif // !BX_USE_UM_SMF
83 UNUSED(io_len);
84
85 Bit32u retval;
86
87 // This function gets called for access to any IO ports which
88 // are not mapped to any device handler. Reads return 0
89
90 if (address >= 0x02e0 && address <= 0x02ef) {
91 retval = 0;
92 goto return_from_read;
93 }
94
95 switch (address) {
96 case 0x80:
97 retval = BX_UM_THIS s.port80;
98 break;
99 case 0x8e:
100 retval = BX_UM_THIS s.port8e;
101 break;
102
103 // Unused port on ISA - this can be used by the emulated code
104 // to detect it is running inside Bochs and that the debugging
105 // features are available (write 0xFF or something on unused
106 // port 0x80, then read from 0xe9, if value is 0xe9, debug
107 // output is available) (see write() for that) -- Andreas and Emmanuel
108 case 0xe9:
109 if (BX_UM_THIS s.port_e9_hack) {
110 retval = 0xe9;
111 }
112 else {
113 retval = 0xffffffff;
114 }
115 break;
116
117 case 0x03df:
118 retval = 0xffffffff;
119 BX_DEBUG(("unsupported IO read from port %04x (CGA)", address));
120 break;
121 case 0x023a:
122 case 0x02f8: /* UART */
123 case 0x02f9: /* UART */
124 case 0x02fb: /* UART */
125 case 0x02fc: /* UART */
126 case 0x02fd: /* UART */
127 case 0x02ea:
128 case 0x02eb:
129 case 0x03e8:
130 case 0x03e9:
131 case 0x03ea:
132 case 0x03eb:
133 case 0x03ec:
134 case 0x03ed:
135 case 0x03f8: /* UART */
136 case 0x03f9: /* UART */
137 case 0x03fb: /* UART */
138 case 0x03fc: /* UART */
139 case 0x03fd: /* UART */
140 case 0x17c6:
141 retval = 0xffffffff;
142 break;
143 default:
144 retval = 0xffffffff;
145 }
146
147 return_from_read:
148
149 switch (io_len) {
150 case 1:
151 retval = (Bit8u)retval;
152 BX_DEBUG(("unmapped: 8-bit read from %04x = %02x", address, retval));
153 break;
154 case 2:
155 retval = (Bit16u)retval;
156 BX_DEBUG(("unmapped: 16-bit read from %04x = %04x", address, retval));
157 break;
158 case 4:
159 BX_DEBUG(("unmapped: 32-bit read from %04x = %08x", address, retval));
160 break;
161 default:
162 BX_PANIC(("unmapped: %d-bit read from %04x = %x", io_len * 8, address, retval));
163 }
164
165 return retval;
166 }
167
168 // static IO port write callback handler
169 // redirects to non-static class handler to avoid virtual functions
170
write_handler(void * this_ptr,Bit32u address,Bit32u value,unsigned io_len)171 void bx_unmapped_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
172 {
173 #if !BX_USE_UM_SMF
174 bx_unmapped_c *class_ptr = (bx_unmapped_c *) this_ptr;
175 class_ptr->write(address, value, io_len);
176 }
177
write(Bit32u address,Bit32u value,unsigned io_len)178 void bx_unmapped_c::write(Bit32u address, Bit32u value, unsigned io_len)
179 {
180 #else
181 UNUSED(this_ptr);
182 #endif // !BX_USE_UM_SMF
183 UNUSED(io_len);
184
185 // This function gets called for access to any IO ports which
186 // are not mapped to any device handler. Writes to an unmapped
187 // IO port are ignored.
188
189 if (address >= 0x02e0 && address <= 0x02ef)
190 goto return_from_write;
191
192 switch (address) {
193 case 0x80: // diagnostic test port to display progress of POST
194 //BX_DEBUG(("Diagnostic port 80h: write = %02xh", (unsigned) value));
195 BX_UM_THIS s.port80 = value;
196 break;
197
198 case 0x8e: // ???
199 BX_UM_THIS s.port8e = value;
200 break;
201
202 // This port doesn't exist on normal ISA architecture. However,
203 // we define a convention here, to display on the console of the
204 // system running Bochs, anything that is written to it. The
205 // idea is to provide debug output very early when writing
206 // BIOS or OS code for example, without having to bother with
207 // properly setting up a serial port or anything.
208 //
209 // Idea by Andreas Beck (andreas.beck@ggi-project.org)
210
211 case 0xe9:
212 if (BX_UM_THIS s.port_e9_hack) {
213 putchar(value);
214 fflush(stdout);
215 }
216 break;
217
218 case 0xed: // Dummy port used as I/O delay
219 break;
220 case 0xee: // ???
221 break;
222
223 case 0x2f2:
224 case 0x2f3:
225 case 0x2f4:
226 case 0x2f5:
227 case 0x2f6:
228 case 0x2f7:
229 case 0x3e8:
230 case 0x3e9:
231 case 0x3eb:
232 case 0x3ec:
233 case 0x3ed:
234 // BX_DEBUG(("unsupported IO write to port %04x of %02x", address, value));
235 break;
236
237 case 0x8900: // Shutdown port, could be moved in a PM device
238 // or a host <-> guest communication device
239 switch (value) {
240 case 'S': if (BX_UM_THIS s.shutdown == 0) BX_UM_THIS s.shutdown = 1; break;
241 case 'h': if (BX_UM_THIS s.shutdown == 1) BX_UM_THIS s.shutdown = 2; break;
242 case 'u': if (BX_UM_THIS s.shutdown == 2) BX_UM_THIS s.shutdown = 3; break;
243 case 't': if (BX_UM_THIS s.shutdown == 3) BX_UM_THIS s.shutdown = 4; break;
244 case 'd': if (BX_UM_THIS s.shutdown == 4) BX_UM_THIS s.shutdown = 5; break;
245 case 'o': if (BX_UM_THIS s.shutdown == 5) BX_UM_THIS s.shutdown = 6; break;
246 case 'w': if (BX_UM_THIS s.shutdown == 6) BX_UM_THIS s.shutdown = 7; break;
247 case 'n': if (BX_UM_THIS s.shutdown == 7) BX_UM_THIS s.shutdown = 8; break;
248 #if BX_DEBUGGER
249 // Very handy for debugging:
250 // output 'D' to port 8900, and bochs quits to debugger
251 case 'D': bx_debug_break(); break;
252 #endif
253 default : BX_UM_THIS s.shutdown = 0; break;
254 }
255 if (BX_UM_THIS s.shutdown == 8) {
256 bx_user_quit = 1;
257 BX_FATAL(("Shutdown port: shutdown requested"));
258 }
259 break;
260 /*
261 case 0xfedc:
262 bx_dbg.io_debugger = (value > 0);
263 BX_DEBUG(("DEBUGGER = %u", (unsigned) bx_dbg.io_debugger));
264 break;
265 */
266 default:
267 break;
268 }
269
270 return_from_write:
271
272 switch (io_len) {
273 case 1:
274 BX_DEBUG(("unmapped: 8-bit write to %04x = %02x", address, value));
275 break;
276 case 2:
277 BX_DEBUG(("unmapped: 16-bit write to %04x = %04x", address, value));
278 break;
279 case 4:
280 BX_DEBUG(("unmapped: 32-bit write to %04x = %08x", address, value));
281 break;
282 default:
283 BX_PANIC(("unmapped: %d-bit write to %04x = %x", io_len * 8, address, value));
284 break;
285 }
286 }
287
param_handler(bx_param_c * param,bool set,Bit64s val)288 Bit64s bx_unmapped_c::param_handler(bx_param_c *param, bool set, Bit64s val)
289 {
290 if (set) {
291 char pname[BX_PATHNAME_LEN];
292 param->get_param_path(pname, BX_PATHNAME_LEN);
293 if (set) {
294 if (!strcmp(pname, BXPN_PORT_E9_HACK)) {
295 BX_UM_THIS s.port_e9_hack = (val != 0);
296 } else {
297 BX_PANIC(("param_handler called with unexpected parameter '%s'", pname));
298 }
299 }
300 }
301 return val;
302 }
303