* [Qemu-devel] [PATCH][RFC] system emulator modularization
@ 2005-01-15 23:51 Magnus Damm
2005-01-16 14:06 ` Andreas Bollhalder
0 siblings, 1 reply; 4+ messages in thread
From: Magnus Damm @ 2005-01-15 23:51 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 3397 bytes --]
Heya,
I have recently been scratching one of my favourite itches:
modularization. QEMU has some well defined interfaces, but one of the
bottlenecks when it comes to add and test new code is IMHO the command
line options. The current way to do it is pretty straight forward -
just add your new command line options to vl.c and off you go.
However, this leads to some kind of option space pollution. With other
words, I do not think the current solution scales wery well and it
would be a shame to make it harder to add code to QEMU than it has to
be.
So, what I would like to add to QEMU is some kind of module support.
My idea consists of two basic building blocks: modules and labels.
A module is some kind of well defined function of the emulator, maybe
code that emulates one chip, or perhaps some core emulator code. You
could call it a class.
A label is a named instance of a module. Each label is associated with
a private data area that contains all state about the label. Pretty
much an object.
So, to be able to use any module you have to create an instance of it
by creating a label. When a label is created it is possible to pass
parameters to the instance. Each module has a set of operations, I
suggest the following:
check():
Called when the label is created. Used to validate module parameters.
Should not allocate any data, private data belonging to label is
already allocated by global module code. Must make sure that the
module parameters are saved in a standardized endian-independent
format - I suggest network byte order.
start():
Called when the label is enabled. The private data is still in network
byte order, now it is time for the module to convert the data to
native byte order, allocate data and register itself or whatever. This
start operation is used both for restore from a saved state and for a
clean start.
stop():
Called when the label is disabled, ie when the emulator is shut down
or when state is saved. The module should unregister itself and
convert the private data into network byte order. After stop() it
should be possible to use the same private data and perform start().
>From the command line it should be possible to create/change labels
and to list availible modules. The attached patch lists modules after
the help text, and the temporary option -x is currently used to create
a label. From the help text:
-x label=module[:args] create one instance of module called label
The grand plan (not finished yet if ever) is that labels should depend
on each other and something like this could be used to start the
emulator with 2 vga cards and one nic on the pci bus:
-x vga0=cirrus-vga
-x vga1=std-vga
-x nic0=ne2000:mac=0x0080deadbe
-x pcibus0=pcibus:vga0,vga1,nic0
-x cpu0=x86:nommx
-x mypc=pc:cpu0,pcibus0
This idea together with predefined profiles (collection of predefined
labels) and that it should be possible to override predefined labels
with user-defined ones would make QEMU pretty flexible IMHO.
The attached patch does not do anything useful, it just contains some
module code and a module skeleton. The code is pretty much a big hack,
but I included it just to let you see. The module code is "inspired"
from the Linux kernel, but improved to support instances. Module
information is stored in a special section, just link in the code
between module.o and module_last.o and everything should work by
itself.
/ magnus
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: qemu-cvs_20050115-modules.patch --]
[-- Type: text/x-patch; name="qemu-cvs_20050115-modules.patch", Size: 9100 bytes --]
diff -urN qemu/Makefile.target qemu-modules/Makefile.target
--- qemu/Makefile.target 2005-01-15 17:53:22.000000000 +0100
+++ qemu-modules/Makefile.target 2005-01-15 21:48:22.603025920 +0100
@@ -290,6 +290,7 @@
# must use static linking to avoid leaving stuff in virtual address space
VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o
VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o
+VL_OBJS+=module.o module_skeleton.o module_last.o
SOUND_HW = sb16.o
AUDIODRV = audio.o noaudio.o wavaudio.o
diff -urN qemu/module.c qemu-modules/module.c
--- qemu/module.c 1970-01-01 01:00:00.000000000 +0100
+++ qemu-modules/module.c 2005-01-15 23:10:31.273754080 +0100
@@ -0,0 +1,178 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "module.h"
+
+static void *__param_first __param_section = NULL;
+
+void module_list_all(void)
+{
+ void *first_module = &__param_first + 1;
+
+ struct module *curr;
+
+ for (curr = first_module; curr->name; curr++) {
+
+ printf("%-15s %s\n", curr->name, curr->descr);
+ }
+}
+
+static struct module *module_find(char *name)
+{
+ void *first_module = &__param_first + 1;
+
+ struct module *curr;
+
+ for (curr = first_module; curr->name; curr++) {
+
+ if (strcmp(name, curr->name) == 0) {
+ return curr;
+ }
+ }
+
+ return NULL;
+}
+
+struct label {
+ struct label *next;
+
+ char *name;
+ char *args;
+ struct module *module;
+ void *private;
+};
+
+struct label *module_label_first = NULL;
+
+static struct label *module_label_find(char *name)
+{
+ struct label *x;
+
+ for (x = module_label_first; x; x = x->next) {
+ if (strcmp(x->name, name) == 0) {
+ return x;
+ }
+ }
+
+ return NULL;
+}
+
+void module_label_remove(const char *name)
+{
+ struct label *x;
+ struct label *p = NULL;
+
+ for (x = module_label_first; x; x = x->next) {
+ if (strcmp(x->name, name) == 0) {
+ if (p) {
+ p->next = x->next;
+ }
+ else {
+ module_label_first = x->next;
+ }
+
+ free(x->name);
+ free(x);
+ return;
+ }
+
+ p = x;
+ }
+}
+
+
+int module_label_create(const char *str)
+{
+ char *s;
+ struct module *module;
+ struct label *label;
+ char *m, *a;
+
+ s = strdup(str);
+
+ if (!s) {
+ goto bad;
+ }
+
+ a = index(s, ':');
+ if (a) {
+ *a = '\0';
+ a++;
+ }
+ else {
+ a = "";
+ }
+
+ m = index(s, '=');
+ if (m) {
+ *m = '\0';
+ }
+ else {
+ goto bad1;
+ }
+ m++;
+
+ module_label_remove(s);
+
+ module = module_find(m);
+
+ if (!module) {
+ goto bad1;
+ }
+
+ label = malloc(sizeof(*label) + module->size_of_priv);
+
+ if (!label) {
+ goto bad1;
+ }
+
+ label->name = s;
+ label->args = a;
+ label->module = module;
+ label->private = label + 1;
+
+ if (module->ops->check(label->private) < 0) {
+ goto bad2;
+ }
+
+ label->next = module_label_first;
+ module_label_first = label;
+
+ return 0;
+
+ bad2:
+ free(label);
+
+ bad1:
+ free(s);
+
+ bad:
+ return -1;
+}
+
+void module_printf(void *priv, const char *format, ...)
+{
+ va_list args;
+ struct label *label = priv;
+
+ label--;
+
+ printf("%s[%s]:", label->module->name, label->name);
+
+ va_start(args, format);
+
+ vprintf(format, args);
+
+ va_end(args);
+}
+
+char *module_args(void *priv)
+{
+ struct label *label = priv;
+
+ label--;
+
+ return label->args;
+}
diff -urN qemu/module.h qemu-modules/module.h
--- qemu/module.h 1970-01-01 01:00:00.000000000 +0100
+++ qemu-modules/module.h 2005-01-15 23:00:45.006880192 +0100
@@ -0,0 +1,78 @@
+
+#ifndef __MODULE_H__
+#define __MODULE_H__
+
+struct module_ops {
+ int (*check)(void *);
+ int (*start)(void *);
+ void (*stop)(void *);
+};
+
+#define MODULE_OP_TYPECHECK(func, ret_ptr_type, arg) \
+static inline ret_ptr_type(*MODULE_OP_TYPECHECK_##func(void))(arg) \
+{ return(func); }
+
+#define MODULE_OPS(check, start, stop, priv) \
+ { (void *)check, (void *)start, (void *)stop }; \
+ MODULE_OP_TYPECHECK(check, int, priv *); \
+ MODULE_OP_TYPECHECK(start, int, priv *); \
+ MODULE_OP_TYPECHECK(stop, void, priv *)
+
+struct module_param {
+ char *name;
+ char *type;
+ char *descr;
+ char *deflt;
+ unsigned int offset;
+};
+
+#define MODULE_PARAM_TYPECHECK(symbol, type) \
+static inline (type) MODULE_PARAM_TYPECHECK_##symbol(void) { return(symbol); }
+
+#define offset_of(type,member) ((unsigned int)(&((type *)0)->member))
+
+#define MODULE_PARAM(name, type, descr, deflt, priv) \
+ { #name, type, descr, #deflt, offset_of(priv, name) }
+
+struct module {
+ char *name;
+ char *type;
+ char *descr;
+ struct module_ops *ops;
+ struct module_param *params;
+ unsigned int no_params;
+ unsigned int size_of_priv;
+};
+
+#if __GNUC__ > 3
+#define __attribute__used__ __attribute__((__used__))
+#elif __GNUC__ == 3
+#if __GNUC_MINOR__ > 3
+#define __attribute__used__ __attribute__((__used__))
+#else
+#define __attribute__used__ __attribute__((__unused__))
+#endif
+#elif __GNUC__ == 2
+#define __attribute__used__ __attribute__((__unused__))
+#else
+#define __attribute__used__
+#endif
+
+#define MODULE(name, type, descr, ops, params, priv) \
+ static struct module const module \
+ __attribute__used__ \
+ __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
+ = { \
+ #name, type, descr, &ops, params, \
+ (sizeof(params) / sizeof(struct module_param)), sizeof(priv) \
+ }
+
+#define __param_section __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *))))
+
+void module_printf(void *priv, const char *format, ...);
+char *module_args(void *priv);
+
+void module_list_all(void);
+int module_label_create(const char *str);
+
+#endif /* __MODULE_H__ */
diff -urN qemu/module_last.c qemu-modules/module_last.c
--- qemu/module_last.c 1970-01-01 01:00:00.000000000 +0100
+++ qemu-modules/module_last.c 2005-01-15 21:25:16.484747928 +0100
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+#include "module.h"
+
+/* the object file generated from this file must be placed at the end */
+
+static void *__param_last __param_section = NULL;
diff -urN qemu/module_skeleton.c qemu-modules/module_skeleton.c
--- qemu/module_skeleton.c 1970-01-01 01:00:00.000000000 +0100
+++ qemu-modules/module_skeleton.c 2005-01-15 23:02:36.227972016 +0100
@@ -0,0 +1,33 @@
+#include "module.h"
+
+struct private {
+ unsigned int foo;
+ char buf[100];
+ int my_bool;
+};
+
+static int check(struct private *p)
+{
+ module_printf(p, " check! my_bool = %d, args are \"%s\"\n",
+ p->my_bool, module_args(p));
+
+ return 0;
+}
+
+static int start(struct private *p)
+{
+ return 0;
+}
+
+static void stop(struct private *p)
+{
+}
+
+static struct module_ops ops = MODULE_OPS(check, start, stop, struct private);
+
+static struct module_param params[] = {
+ MODULE_PARAM(my_bool, "bool", "a bool parameter called my_bool",
+ xx, struct private),
+};
+
+MODULE(skel, "", "a simple module skeleton", ops, params, struct private);
diff -urN qemu/vl.c qemu-modules/vl.c
--- qemu/vl.c 2005-01-16 00:27:05.974253432 +0100
+++ qemu-modules/vl.c 2005-01-15 23:24:54.956454352 +0100
@@ -76,6 +76,8 @@
#include "exec-all.h"
+#include "module.h"
+
//#define DO_TB_FLUSH
#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
@@ -2769,6 +2771,7 @@
" (default is CL-GD5446 PCI VGA)\n"
#endif
"-loadvm file start right away with a saved state (loadvm in monitor)\n"
+ "-x label=module[:args] create one instance of module called label\n"
"\n"
"During emulation, the following keys are useful:\n"
"ctrl-alt-f toggle full screen\n"
@@ -2792,6 +2795,11 @@
"work. Please use the 'qemu' executable to have a more accurate (but slower)\n"
"PC emulation.\n");
#endif
+
+ printf("\nAvailable modules:\n");
+ module_list_all();
+
+
exit(1);
}
@@ -2848,6 +2856,7 @@
QEMU_OPTION_loadvm,
QEMU_OPTION_full_screen,
QEMU_OPTION_pidfile,
+ QEMU_OPTION_set_module,
};
typedef struct QEMUOption {
@@ -2915,6 +2924,7 @@
/* temporary options */
{ "pci", 0, QEMU_OPTION_pci },
{ "cirrusvga", 0, QEMU_OPTION_cirrusvga },
+ { "x", HAS_ARG, QEMU_OPTION_set_module },
{ NULL },
};
@@ -3328,6 +3338,12 @@
graphic_depth = depth;
}
break;
+ case QEMU_OPTION_set_module:
+ if (module_label_create(optarg) < 0) {
+ fprintf(stderr, "qemu: unable to create label \"%s\"\n", optarg);
+ exit(1);
+ }
+ break;
case QEMU_OPTION_monitor:
pstrcpy(monitor_device, sizeof(monitor_device), optarg);
break;
^ permalink raw reply [flat|nested] 4+ messages in thread
* RE: [Qemu-devel] [PATCH][RFC] system emulator modularization
2005-01-15 23:51 [Qemu-devel] [PATCH][RFC] system emulator modularization Magnus Damm
@ 2005-01-16 14:06 ` Andreas Bollhalder
2005-01-16 20:31 ` Sylvain Petreolle
0 siblings, 1 reply; 4+ messages in thread
From: Andreas Bollhalder @ 2005-01-16 14:06 UTC (permalink / raw)
To: 'Magnus Damm', qemu-devel
I would welcome this concept for configuring QEmu. Also, if this
directives could be stored in a INI file, it would be very cool.
Andreas
> -----Original Message-----
> From: qemu-devel-bounces+bolle=geodb.org@nongnu.org
> [mailto:qemu-devel-bounces+bolle=geodb.org@nongnu.org] On
> Behalf Of Magnus Damm
> Sent: Sunday, January 16, 2005 12:52 AM
> To: qemu-devel@nongnu.org
> Subject: [Qemu-devel] [PATCH][RFC] system emulator modularization
>
>
> Heya,
>
> I have recently been scratching one of my favourite itches:
> modularization. QEMU has some well defined interfaces, but one of
the
> bottlenecks when it comes to add and test new code is IMHO the
command
> line options. The current way to do it is pretty straight forward -
> just add your new command line options to vl.c and off you go.
> However, this leads to some kind of option space pollution. With
other
> words, I do not think the current solution scales wery well and it
> would be a shame to make it harder to add code to QEMU than it has
to
> be.
>
> So, what I would like to add to QEMU is some kind of module support.
> My idea consists of two basic building blocks: modules and labels.
>
> A module is some kind of well defined function of the emulator,
maybe
> code that emulates one chip, or perhaps some core emulator code. You
> could call it a class.
>
> A label is a named instance of a module. Each label is associated
with
> a private data area that contains all state about the label. Pretty
> much an object.
>
> So, to be able to use any module you have to create an instance of
it
> by creating a label. When a label is created it is possible to pass
> parameters to the instance. Each module has a set of operations, I
> suggest the following:
>
> check():
> Called when the label is created. Used to validate module
parameters.
> Should not allocate any data, private data belonging to label is
> already allocated by global module code. Must make sure that the
> module parameters are saved in a standardized endian-independent
> format - I suggest network byte order.
>
> start():
> Called when the label is enabled. The private data is still in
network
> byte order, now it is time for the module to convert the data to
> native byte order, allocate data and register itself or whatever.
This
> start operation is used both for restore from a saved state and for
a
> clean start.
>
> stop():
> Called when the label is disabled, ie when the emulator is shut down
> or when state is saved. The module should unregister itself and
> convert the private data into network byte order. After stop() it
> should be possible to use the same private data and perform start().
>
> >From the command line it should be possible to create/change labels
> and to list availible modules. The attached patch lists modules
after
> the help text, and the temporary option -x is currently used to
create
> a label. From the help text:
>
> -x label=module[:args] create one instance of module called label
>
> The grand plan (not finished yet if ever) is that labels should
depend
> on each other and something like this could be used to start the
> emulator with 2 vga cards and one nic on the pci bus:
>
> -x vga0=cirrus-vga
> -x vga1=std-vga
> -x nic0=ne2000:mac=0x0080deadbe
> -x pcibus0=pcibus:vga0,vga1,nic0
> -x cpu0=x86:nommx
> -x mypc=pc:cpu0,pcibus0
>
> This idea together with predefined profiles (collection of
predefined
> labels) and that it should be possible to override predefined labels
> with user-defined ones would make QEMU pretty flexible IMHO.
>
> The attached patch does not do anything useful, it just contains
some
> module code and a module skeleton. The code is pretty much a big
hack,
> but I included it just to let you see. The module code is "inspired"
> from the Linux kernel, but improved to support instances. Module
> information is stored in a special section, just link in the code
> between module.o and module_last.o and everything should work by
> itself.
>
> / magnus
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* RE: [Qemu-devel] [PATCH][RFC] system emulator modularization
2005-01-16 14:06 ` Andreas Bollhalder
@ 2005-01-16 20:31 ` Sylvain Petreolle
2005-01-16 21:30 ` Magnus Damm
0 siblings, 1 reply; 4+ messages in thread
From: Sylvain Petreolle @ 2005-01-16 20:31 UTC (permalink / raw)
To: bolle, qemu-devel
Hey, why not do as simple as you can ?
myscript
#!/bin/bash
qemu -options -hda /somewhere/myimage
--- Andreas Bollhalder <bolle@geodb.org> a écrit :
> I would welcome this concept for configuring QEmu. Also, if this
> directives could be stored in a INI file, it would be very cool.
>
> Andreas
>
=====
Sylvain Petreolle (spetreolle_at_users.sourceforge.net)
humans are like computers,
yesterday the BIOS was all
- today its just a word
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] [PATCH][RFC] system emulator modularization
2005-01-16 20:31 ` Sylvain Petreolle
@ 2005-01-16 21:30 ` Magnus Damm
0 siblings, 0 replies; 4+ messages in thread
From: Magnus Damm @ 2005-01-16 21:30 UTC (permalink / raw)
To: spetreolle, qemu-devel
On Sun, 16 Jan 2005 21:31:35 +0100 (CET), Sylvain Petreolle
<spetreolle@yahoo.fr> wrote:
> Hey, why not do as simple as you can ?
>
> myscript
> #!/bin/bash
> qemu -options -hda /somewhere/myimage
I agree that "keep it simple" is the best way of doing things, but I
think a host-os independent way to load/save configuration would be
very useful. It allows people to swap configurations with each other
regardless of host operating system which is one step in the right
direction IMHO...
/ magnus
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2005-01-16 21:59 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-01-15 23:51 [Qemu-devel] [PATCH][RFC] system emulator modularization Magnus Damm
2005-01-16 14:06 ` Andreas Bollhalder
2005-01-16 20:31 ` Sylvain Petreolle
2005-01-16 21:30 ` Magnus Damm
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).