1----------------------------------------------------------------------
2Patch name: patch.example-user-plugin
3Author:     Volker Ruppert
4Updated:    7 Feb 2021
5Status:     Demo
6
7Detailed description:
8  This sample code can be used as a framework for writing own optional
9  device plugins (AKA "user plugins). It contains enough code for testing
10  the existing plugin device support in Bochs and creates a device that
11  installs a 32-bit r/w register at i/o address 0x1000.
12  This example also shows how to install and handle user-defined config
13  options for bochsrc, command line and the config interface. In this
14  demo it is used to specify the reset value.
15  For user plugin support Bochs must be configured with plugins enabled.
16  Compiling with plugin support is known to work on Linux and Windows
17  (Cygwin, MinGW/MSYS and MSVC nmake / gui). This sample plugin can be
18  loaded in bochsrc either with "plugin_ctrl" or with it's own name:
19
20  plugin_ctrl: testdev=1
21
22  testdev: testval=1
23
24Patch was created with:
25  diff -u
26Apply patch to what version:
27  svn revision 14132 (Feb 7, 2021)
28Instructions:
29  To patch, go to main bochs directory.
30  Type "patch -p0 < THIS_PATCH_FILE".
31  Configure and compile Bochs as usual
32  cd user-plugins
33  make
34  make install
35----------------------------------------------------------------------
36diff -urN ../bochs/user_plugins/Makefile.in ./user_plugins/Makefile.in
37--- ../bochs/user_plugins/Makefile.in	1970-01-01 01:00:00.000000000 +0100
38+++ ./user_plugins/Makefile.in	2021-02-07 19:08:10.591961411 +0100
39@@ -0,0 +1,112 @@
40+# Copyright (C) 2009-2021  Volker Ruppert
41+#
42+# This library is free software; you can redistribute it and/or
43+# modify it under the terms of the GNU Lesser General Public
44+# License as published by the Free Software Foundation; either
45+# version 2 of the License, or (at your option) any later version.
46+#
47+# This library is distributed in the hope that it will be useful,
48+# but WITHOUT ANY WARRANTY; without even the implied warranty of
49+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
50+# Lesser General Public License for more details.
51+#
52+# You should have received a copy of the GNU Lesser General Public
53+# License along with this library; if not, write to the Free Software
54+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
55+
56+# Makefile for the user plugin example of bochs
57+
58+
59+@SUFFIX_LINE@
60+
61+prefix          = @prefix@
62+exec_prefix     = @exec_prefix@
63+srcdir          = @srcdir@
64+VPATH = @srcdir@
65+bindir          = @bindir@
66+libdir          = @libdir@
67+plugdir         = @libdir@/bochs/plugins
68+datarootdir     = @datarootdir@
69+mandir          = @mandir@
70+man1dir         = $(mandir)/man1
71+man5dir         = $(mandir)/man5
72+docdir          = $(datarootdir)/doc/bochs
73+sharedir        = $(datarootdir)/bochs
74+top_builddir    = ..
75+top_srcdir      = @top_srcdir@
76+
77+SHELL = @SHELL@
78+
79+@SET_MAKE@
80+
81+CXX = @CXX@
82+CXXFLAGS = $(BX_INCDIRS) @CXXFLAGS@ @GUI_CXXFLAGS@
83+
84+LDFLAGS = @LDFLAGS@
85+LIBS = @LIBS@
86+RANLIB = @RANLIB@
87+PLUGIN_PATH=@libdir@
88+top_builddir    = ..
89+LIBTOOL=@LIBTOOL@
90+WIN32_DLL_IMPORT_LIBRARY=../@WIN32_DLL_IMPORT_LIB@
91+
92+BX_INCDIRS = -I.. -I$(srcdir)/.. -I../iodev -I$(srcdir)/../iodev -I../@INSTRUMENT_DIR@ -I$(srcdir)/../@INSTRUMENT_DIR@
93+
94+PLUGIN_OBJS = testdev.o
95+
96+plugins: @PLUGIN_TARGET_2@
97+
98+plugins_gcc: $(PLUGIN_OBJS:@PLUGIN_LIBNAME_TRANSFORMATION@)
99+
100+plugins_msvc: bx_testdev.dll
101+
102+install: @INSTALL_PLUGINS_VAR@
103+
104+install_libtool_plugins::
105+	list=`echo *.la`; for i in $$list; do $(LIBTOOL) --mode=install install $$i $(DESTDIR)$(plugdir); done
106+	$(LIBTOOL) --finish $(DESTDIR)$(plugdir)
107+
108+install_dll_plugins::
109+	list=`echo *.dll`; for i in $$list; do cp $$i $(DESTDIR)$(plugdir); done
110+
111+# standard compile rule for C++ files
112+.@CPP_SUFFIX@.o:
113+	$(CXX) @DASH@c  $(CXXFLAGS) $(LOCAL_CXXFLAGS) @CXXFP@$< @OFP@$@
114+
115+##### building plugins with libtool
116+%.lo: %.@CPP_SUFFIX@
117+	$(LIBTOOL) --mode=compile $(CXX) -c $(CXXFLAGS) $(LOCAL_CXXFLAGS) $< -o $@
118+
119+libbx_%.la: %.lo
120+	$(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH)
121+
122+# special link rules for plugins with Cygwin, MinGW/MSYS and MSVC nmake
123+bx_testdev.dll: testdev.o
124+	@LINK_DLL@ testdev.o $(WIN32_DLL_IMPORT_LIBRARY)
125+
126+clean:
127+	@RMCOMMAND@ -rf .libs *.lo *.o *.la *.a *.dll *.exp *.lib *.dll.manifest
128+
129+dist-clean: clean
130+	@RMCOMMAND@ Makefile
131+
132+###########################################
133+# dependencies generated by
134+#  gcc -MM -I.. -I../instrument/stubs *.cc | sed -e 's/\.cc/.@CPP_SUFFIX@/g'
135+#  gcc -MM -I.. -I../instrument/stubs *.cc | \
136+#     sed -e 's/\.cc/.@CPP_SUFFIX@/g' -e 's/\.o:/.lo:/g'
137+#
138+# This means that every source file is listed twice, once with a .o rule
139+# and then again with an identical .lo rule.  The .lo rules are used when
140+# building plugins.
141+###########################################
142+testdev.o: testdev.@CPP_SUFFIX@ ../iodev/iodev.h ../bochs.h ../config.h ../osdep.h \
143+ ../bx_debug/debug.h ../config.h ../osdep.h ../gui/siminterface.h \
144+ ../cpudb.h ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h \
145+ ../gui/gui.h ../instrument/stubs/instrument.h ../plugin.h ../extplugin.h \
146+ ../param_names.h testdev.h
147+testdev.lo: testdev.@CPP_SUFFIX@ ../iodev/iodev.h ../bochs.h ../config.h ../osdep.h \
148+ ../bx_debug/debug.h ../config.h ../osdep.h ../gui/siminterface.h \
149+ ../cpudb.h ../gui/paramtree.h ../memory/memory-bochs.h ../pc_system.h \
150+ ../gui/gui.h ../instrument/stubs/instrument.h ../plugin.h ../extplugin.h \
151+ ../param_names.h testdev.h
152diff -urN ../bochs/user_plugins/testdev.cc ./user_plugins/testdev.cc
153--- ../bochs/user_plugins/testdev.cc	1970-01-01 01:00:00.000000000 +0100
154+++ ./user_plugins/testdev.cc	2021-02-07 19:26:36.000020446 +0100
155@@ -0,0 +1,127 @@
156+// Copyright (C) 2009-2021  Volker Ruppert
157+//
158+// This library is free software; you can redistribute it and/or
159+// modify it under the terms of the GNU Lesser General Public
160+// License as published by the Free Software Foundation; either
161+// version 2 of the License, or (at your option) any later version.
162+//
163+// This library is distributed in the hope that it will be useful,
164+// but WITHOUT ANY WARRANTY; without even the implied warranty of
165+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
166+// Lesser General Public License for more details.
167+//
168+// You should have received a copy of the GNU Lesser General Public
169+// License along with this library; if not, write to the Free Software
170+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
171+
172+// User plugin example (see patch description for details)
173+
174+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
175+// platforms that require a special tag on exported symbols, BX_PLUGGABLE
176+// is used to know when we are exporting symbols and when we are importing.
177+#define BX_PLUGGABLE
178+
179+#include "iodev.h"
180+#include "testdev.h"
181+
182+#define LOG_THIS theTestDevice->
183+
184+bx_testdev_c *theTestDevice = NULL;
185+
186+// builtin configuration handling functions
187+
188+void testdev_init_options(void)
189+{
190+  bx_param_c *root_param = SIM->get_param("user");
191+  bx_list_c *menu = new bx_list_c(root_param, "testdev", "Test Device");
192+  menu->set_options(bx_list_c::SHOW_PARENT);
193+  new bx_param_bool_c(menu, "enabled", "Enable Test device", "", 1);
194+  new bx_param_num_c(menu, "testval", "Test Parameter", "", 0, BX_MAX_BIT32U, 0);
195+}
196+
197+Bit32s testdev_options_parser(const char *context, int num_params, char *params[])
198+{
199+  if (!strcmp(params[0], "testdev")) {
200+    bx_list_c *base = (bx_list_c*) SIM->get_param("user.testdev");
201+    for (int i = 1; i < num_params; i++) {
202+      if (SIM->parse_param_from_list(context, params[i], base) < 0) {
203+        BX_ERROR(("%s: unknown parameter for testdev ignored.", context));
204+      }
205+    }
206+  } else {
207+    BX_PANIC(("%s: unknown directive '%s'", context, params[0]));
208+  }
209+  return 0;
210+}
211+
212+Bit32s testdev_options_save(FILE *fp)
213+{
214+  return SIM->write_param_list(fp, (bx_list_c*) SIM->get_param("user.testdev"), NULL, 0);
215+}
216+
217+// device plugin entry point
218+
219+PLUGIN_ENTRY_FOR_MODULE(testdev)
220+{
221+  if (mode == PLUGIN_INIT) {
222+    theTestDevice = new bx_testdev_c();
223+    BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theTestDevice, "testdev");
224+    // add new configuration parameter for the config interface
225+    testdev_init_options();
226+    // register user-defined option for bochsrc and command line
227+    SIM->register_addon_option("testdev", testdev_options_parser, testdev_options_save);
228+  } else if (mode == PLUGIN_FINI) {
229+    SIM->unregister_addon_option("testdev");
230+    bx_list_c *menu = (bx_list_c*)SIM->get_param("user");
231+    menu->remove("testdev");
232+    delete theTestDevice;
233+  } else {
234+    return (int)PLUGTYPE_OPTIONAL;
235+  }
236+  return(0); // Success
237+}
238+
239+// the device object
240+
241+bx_testdev_c::bx_testdev_c(void)
242+{
243+  put("USER");
244+}
245+
246+bx_testdev_c::~bx_testdev_c(void)
247+{
248+  // nothing here yet
249+}
250+
251+void bx_testdev_c::init(void)
252+{
253+  if (!SIM->get_param_num("user.testdev.enabled")->get())
254+    return;
255+  DEV_register_ioread_handler(this, read_handler, 0x1000, "Test Device", 4);
256+  DEV_register_iowrite_handler(this, write_handler, 0x1000, "Test Device", 4);
257+}
258+
259+void bx_testdev_c::reset(unsigned type)
260+{
261+  BX_USER_THIS s.reg0 = SIM->get_param_num("user.testdev.testval")->get();
262+}
263+
264+void bx_testdev_c::register_state(void)
265+{
266+  bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "testdev", "Test Device");
267+  BXRS_HEX_PARAM_FIELD(list, reg0, BX_USER_THIS s.reg0);
268+}
269+
270+Bit32u bx_testdev_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
271+{
272+  UNUSED(this_ptr);
273+
274+  return BX_USER_THIS s.reg0;
275+}
276+
277+void bx_testdev_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
278+{
279+  UNUSED(this_ptr);
280+
281+  BX_USER_THIS s.reg0 = value;
282+}
283diff -urN ../bochs/user_plugins/testdev.h ./user_plugins/testdev.h
284--- ../bochs/user_plugins/testdev.h	1970-01-01 01:00:00.000000000 +0100
285+++ ./user_plugins/testdev.h	2021-02-07 19:08:10.591961411 +0100
286@@ -0,0 +1,40 @@
287+// Copyright (C) 2009-2021  Volker Ruppert
288+//
289+// This library is free software; you can redistribute it and/or
290+// modify it under the terms of the GNU Lesser General Public
291+// License as published by the Free Software Foundation; either
292+// version 2 of the License, or (at your option) any later version.
293+//
294+// This library is distributed in the hope that it will be useful,
295+// but WITHOUT ANY WARRANTY; without even the implied warranty of
296+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
297+// Lesser General Public License for more details.
298+//
299+// You should have received a copy of the GNU Lesser General Public
300+// License along with this library; if not, write to the Free Software
301+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
302+
303+#ifndef BX_TESTDEV_H
304+#define BX_TESTDEV_H
305+
306+#define BX_USER_THIS theTestDevice->
307+
308+class bx_testdev_c : public bx_devmodel_c {
309+public:
310+  bx_testdev_c();
311+  virtual ~bx_testdev_c();
312+
313+  virtual void init(void);
314+  virtual void reset(unsigned type);
315+  virtual void register_state(void);
316+
317+private:
318+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
319+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
320+
321+  struct {
322+    Bit32u reg0;
323+  } s;
324+};
325+
326+#endif
327