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