Message ID | 1298497114-7436-1-git-send-email-aliguori@us.ibm.com |
---|---|
State | New |
Headers | show |
Anthony Liguori <aliguori@us.ibm.com> wrote: > The goal is to enable the monitor to run independently of whether the machine > has been created such that the monitor can be used to specify all of the > parameters for machine initialization. > > Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> I agree that it is one step in the right direction, but we are still calling qemu_machine_init() before calling the main_loop(). What is the plan from here? Later, Juan.
On 02/23/2011 05:00 PM, Juan Quintela wrote: > Anthony Liguori<aliguori@us.ibm.com> wrote: > >> The goal is to enable the monitor to run independently of whether the machine >> has been created such that the monitor can be used to specify all of the >> parameters for machine initialization. >> >> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com> >> > I agree that it is one step in the right direction, but we are still > calling qemu_machine_init() before calling the main_loop(). > > What is the plan from here? > 1) Decouple QMP from qemu_machine_init(). This really requires the introduction of the new QAPI server that exists outside of the chardev infrastructure since chardevs are currently initialized in qemu_machine_init(). 2) Make qemu_machine_init() take no parameters and just reference global state. 3) Teach all QMP functions to behave themselves if called before qemu_machine_init() 4) Introduce QMP function to call qemu_machine_init() 5) Introduce new command line flag to not automatically call qemu_machine_init() 6) Convert all command line options to just be QMP function calls (6) can be started right now. (1) comes with the QAPI merge. (2) is pretty easy to do after applying this patch. (3) is probably something that can be done shortly after (1). (4) and (5) really require everything but (6) to be in place before we can meaningful do it. I think we can lay out much of the ground work for this in 0.15 and I think we can have a total conversion realistically for 0.16. That means that by EOY, we could invoke QEMU with no options and do everything through QMP. Somewhere in all of this, we need to fit in a stateful (non-)config file too IMHO. Regards, Anthony Liguori > Later, Juan. > >
Anthony Liguori <anthony@codemonkey.ws> wrote: > On 02/23/2011 05:00 PM, Juan Quintela wrote: >> Anthony Liguori<aliguori@us.ibm.com> wrote: >> >>> The goal is to enable the monitor to run independently of whether the machine >>> has been created such that the monitor can be used to specify all of the >>> parameters for machine initialization. >>> >>> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com> >>> >> I agree that it is one step in the right direction, but we are still >> calling qemu_machine_init() before calling the main_loop(). >> >> What is the plan from here? >> > > 1) Decouple QMP from qemu_machine_init(). This really requires the > introduction of the new QAPI server that exists outside of the chardev > infrastructure since chardevs are currently initialized in > qemu_machine_init(). > > 2) Make qemu_machine_init() take no parameters and just reference > global state. Any good idea how that global state is going to be stored? I just want to be able to launch a qemu on a different machine and migrate the "configuration" to it, for doing that, I really need what values are different from default or anything like that. So as you can see, I am very interested on that work. Later, Juan.
On 02/23/2011 05:38 PM, Juan Quintela wrote: > Anthony Liguori<anthony@codemonkey.ws> wrote: > >> On 02/23/2011 05:00 PM, Juan Quintela wrote: >> >>> Anthony Liguori<aliguori@us.ibm.com> wrote: >>> >>> >>>> The goal is to enable the monitor to run independently of whether the machine >>>> has been created such that the monitor can be used to specify all of the >>>> parameters for machine initialization. >>>> >>>> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com> >>>> >>>> >>> I agree that it is one step in the right direction, but we are still >>> calling qemu_machine_init() before calling the main_loop(). >>> >>> What is the plan from here? >>> >>> >> 1) Decouple QMP from qemu_machine_init(). This really requires the >> introduction of the new QAPI server that exists outside of the chardev >> infrastructure since chardevs are currently initialized in >> qemu_machine_init(). >> >> 2) Make qemu_machine_init() take no parameters and just reference >> global state. >> > Any good idea how that global state is going to be stored? > > I just want to be able to launch a qemu on a different machine and > migrate the "configuration" to it, for doing that, I really need what > values are different from default or anything like that. So as you can > see, I am very interested on that work. > First step is to have everything go through QMP. If everything flows through QMP, we have a gateway that we can focus on. What I'd like to do next is introduce the notion of a stateful config file. This config file is essentially a global database that can be used to store information about the guest from within QEMU. So -name would become: case QEMU_OPTION_name: qmp_set_name(optarg, NULL); break; } And qmp_set_name woudl be implemented as: static const char *qemu_name; void qmp_set_name(const char *name, Error **errp) { qemu_name = name; } char *qmp_query_name(Error **errp) { return qemu_strdup(qemu_name); } Now, to integrate this into the stateful config file, we would do something like: void qmp_set_name(const char *name, Error **errp) { qemu_set_config("global", "name", name); } char *qmp_query_name(Error **errp) { return qemu_strdup(qemu_get_config("global", "name")); } This is a simplistic example and more complex examples have not been totally thought out, but this is where I'm looking to go. Regards, Anthony Liguori > Later, Juan. > >
On Thu, Feb 24, 2011 at 12:36 AM, Anthony Liguori <anthony@codemonkey.ws> wrote: > On 02/23/2011 05:38 PM, Juan Quintela wrote: >> >> Anthony Liguori<anthony@codemonkey.ws> wrote: >> >>> >>> On 02/23/2011 05:00 PM, Juan Quintela wrote: >>> >>>> >>>> Anthony Liguori<aliguori@us.ibm.com> wrote: >>>> >>>> >>>>> >>>>> The goal is to enable the monitor to run independently of whether the >>>>> machine >>>>> has been created such that the monitor can be used to specify all of >>>>> the >>>>> parameters for machine initialization. >>>>> >>>>> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com> >>>>> >>>>> >>>> >>>> I agree that it is one step in the right direction, but we are still >>>> calling qemu_machine_init() before calling the main_loop(). >>>> >>>> What is the plan from here? >>>> >>>> >>> >>> 1) Decouple QMP from qemu_machine_init(). This really requires the >>> introduction of the new QAPI server that exists outside of the chardev >>> infrastructure since chardevs are currently initialized in >>> qemu_machine_init(). >>> >>> 2) Make qemu_machine_init() take no parameters and just reference >>> global state. >>> >> >> Any good idea how that global state is going to be stored? >> >> I just want to be able to launch a qemu on a different machine and >> migrate the "configuration" to it, for doing that, I really need what >> values are different from default or anything like that. So as you can >> see, I am very interested on that work. >> > > First step is to have everything go through QMP. If everything flows > through QMP, we have a gateway that we can focus on. > > What I'd like to do next is introduce the notion of a stateful config file. Any chance of reusing info qtree, QemuOpts, or other existing infrastructure for the config file? Config file set/get/format code tends to be just toggling variables and manipulating strings. There is similarity here with the option parsing and qdev properties. Stefan
On 02/24/2011 04:19 AM, Stefan Hajnoczi wrote: > > Any chance of reusing info qtree, QemuOpts, or other existing > infrastructure for the config file? > I'm nowhere near implementation details like that. I'm still trying to understand whether this is a Good Idea at all. Regards, Anthony Liguori > Config file set/get/format code tends to be just toggling variables > and manipulating strings. There is similarity here with the option > parsing and qdev properties. > > Stefan > >
On 02/24/2011 01:12 AM, Anthony Liguori wrote: >> What is the plan from here? > > > 1) Decouple QMP from qemu_machine_init(). This really requires the > introduction of the new QAPI server that exists outside of the chardev > infrastructure since chardevs are currently initialized in > qemu_machine_init(). Is it really necessary? What's blocking us from initializing chardevs early? It would be a pity to divorce the monitor from chardevs, they're really flexible. > 2) Make qemu_machine_init() take no parameters and just reference > global state. > > 3) Teach all QMP functions to behave themselves if called before > qemu_machine_init() > > 4) Introduce QMP function to call qemu_machine_init() An alternative is to remove all guest-visible content from qemu_machine_init(). So machine->init() would take no parameters and only build the static devices (power supply?). Everything else would be hot-plugged (perhaps some would fail if the machine was started - cold-plug only). > > 5) Introduce new command line flag to not automatically call > qemu_machine_init() > > 6) Convert all command line options to just be QMP function calls > > (6) can be started right now. (1) comes with the QAPI merge. (2) is > pretty easy to do after applying this patch. (3) is probably > something that can be done shortly after (1). (4) and (5) really > require everything but (6) to be in place before we can meaningful do it. > > I think we can lay out much of the ground work for this in 0.15 and I > think we can have a total conversion realistically for 0.16. That > means that by EOY, we could invoke QEMU with no options and do > everything through QMP. It's something that I've agitated for a long while, but when I see all the work needed, I'm not sure it's cost effective.
On 02/24/2011 10:01 AM, Avi Kivity wrote: > On 02/24/2011 01:12 AM, Anthony Liguori wrote: >>> What is the plan from here? >> >> >> 1) Decouple QMP from qemu_machine_init(). This really requires the >> introduction of the new QAPI server that exists outside of the >> chardev infrastructure since chardevs are currently initialized in >> qemu_machine_init(). > > Is it really necessary? What's blocking us from initializing chardevs > early? Well.... We initialize all chardevs at once right now and what set of chardevs there are depends on the machine (by the way defaults are applied). You could initialize chardevs in two stages although that requires quite a bit of additional complexity. > > It would be a pity to divorce the monitor from chardevs, they're > really flexible. Couple considerations: 1) chardevs don't support multiple simultaneous connections. I view this as a blocker for QMP. 2) Because chardevs don't support multiple connections, we can't reasonably hook on things like connect/disconnect which means that fd's sent via SCM_RIGHTs have to be handled in a very special way. By going outside of the chardev layer, we can let fd's via SCM_RIGHTS queue up naturally and have getfd/setfd refer to the fd at the top of the queue. It makes it quite a bit easier to work with (I believe Daniel had actually requested this a while ago). 3) By treating QMP as a special case, we don't have to treat chardevs overall as a special case. This feels more right to me although I can't say I have a strong opinion formed yet. > >> 2) Make qemu_machine_init() take no parameters and just reference >> global state. >> >> 3) Teach all QMP functions to behave themselves if called before >> qemu_machine_init() >> >> 4) Introduce QMP function to call qemu_machine_init() > > An alternative is to remove all guest-visible content from > qemu_machine_init(). So machine->init() would take no parameters and > only build the static devices (power supply?). Everything else would > be hot-plugged (perhaps some would fail if the machine was started - > cold-plug only). All that qemu_machine_init() is is guest-visible content. That's the point of refactoring this. >> >> 5) Introduce new command line flag to not automatically call >> qemu_machine_init() >> >> 6) Convert all command line options to just be QMP function calls >> >> (6) can be started right now. (1) comes with the QAPI merge. (2) is >> pretty easy to do after applying this patch. (3) is probably >> something that can be done shortly after (1). (4) and (5) really >> require everything but (6) to be in place before we can meaningful do >> it. >> >> I think we can lay out much of the ground work for this in 0.15 and I >> think we can have a total conversion realistically for 0.16. That >> means that by EOY, we could invoke QEMU with no options and do >> everything through QMP. > > It's something that I've agitated for a long while, but when I see all > the work needed, I'm not sure it's cost effective. There's a lot of secondary benefits that come from doing this. QMP becomes a much stronger interface. A lot of operations that right now are only specifiable by the command line become dynamic which mitigates reboots in the long term. It also lays the ground work for a fully decoupled device model whereas the only interface between the devices and the outside world is a subset of QMP (think seccomp()). Whether creating a machine with no command line options is high value is probably irrelevant. I think we want to go in this direction regardless. Regards, Anthony Liguori
On Wed, Feb 23, 2011 at 11:38 PM, Anthony Liguori <aliguori@us.ibm.com> wrote: > The goal is to enable the monitor to run independently of whether the machine > has been created such that the monitor can be used to specify all of the > parameters for machine initialization. > > Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> > > diff --git a/vl.c b/vl.c > index b436952..181cc77 100644 > --- a/vl.c > +++ b/vl.c > @@ -1917,17 +1917,360 @@ static const QEMUOption *lookup_opt(int argc, char **argv, > return popt; > } > > +static int qemu_machine_init(QEMUMachine *machine, const char *kernel_filename, > + const char *kernel_cmdline, > + const char *initrd_filename, > + const char *boot_devices, const char *cpu_model, > + int snapshot, int tb_size, const char *gdbstub_dev, > + const char *loadvm, const char *incoming) qemu_machine_init() would mix host state initialization and machine initialization. I'd make instead two functions, qemu_host_init() and qemu_machine_init(). For example parameters snapshot, tb_size, gdbstub_dev, (maybe also loadvm and incoming if handled elsewhere) do not change how the machine is initialized. Also KVM, drive, chardev and display init should go to qemu_host_init() if possible.
On 02/24/2011 07:25 PM, Anthony Liguori wrote: >> Is it really necessary? What's blocking us from initializing >> chardevs early? > > > Well.... > > We initialize all chardevs at once right now and what set of chardevs > there are depends on the machine (by the way defaults are applied). > You could initialize chardevs in two stages although that requires > quite a bit of additional complexity. We could initialize chardevs on demand - that should resolve any dependencies? > >> >> It would be a pity to divorce the monitor from chardevs, they're >> really flexible. > > Couple considerations: > > 1) chardevs don't support multiple simultaneous connections. I view > this as a blocker for QMP. What do you mean by that? Something like ,server which keeps on listening after it a connection is established? > > 2) Because chardevs don't support multiple connections, we can't > reasonably hook on things like connect/disconnect which means that > fd's sent via SCM_RIGHTs have to be handled in a very special way. By > going outside of the chardev layer, we can let fd's via SCM_RIGHTS > queue up naturally and have getfd/setfd refer to the fd at the top of > the queue. It makes it quite a bit easier to work with (I believe > Daniel had actually requested this a while ago). I really don't follow... what's the connection between SCM_RIGHTS and multiple connections? > 3) By treating QMP as a special case, we don't have to treat chardevs > overall as a special case. This feels more right to me although I > can't say I have a strong opinion formed yet. > >> >>> 2) Make qemu_machine_init() take no parameters and just reference >>> global state. >>> >>> 3) Teach all QMP functions to behave themselves if called before >>> qemu_machine_init() >>> >>> 4) Introduce QMP function to call qemu_machine_init() >> >> An alternative is to remove all guest-visible content from >> qemu_machine_init(). So machine->init() would take no parameters and >> only build the static devices (power supply?). Everything else would >> be hot-plugged (perhaps some would fail if the machine was started - >> cold-plug only). > > All that qemu_machine_init() is is guest-visible content. That's the > point of refactoring this. Sorry, poorly phrased. Configurable guest visible content. >>> >>> (6) can be started right now. (1) comes with the QAPI merge. (2) >>> is pretty easy to do after applying this patch. (3) is probably >>> something that can be done shortly after (1). (4) and (5) really >>> require everything but (6) to be in place before we can meaningful >>> do it. >>> >>> I think we can lay out much of the ground work for this in 0.15 and >>> I think we can have a total conversion realistically for 0.16. That >>> means that by EOY, we could invoke QEMU with no options and do >>> everything through QMP. >> >> It's something that I've agitated for a long while, but when I see >> all the work needed, I'm not sure it's cost effective. > > There's a lot of secondary benefits that come from doing this. QMP > becomes a much stronger interface. A lot of operations that right now > are only specifiable by the command line become dynamic which > mitigates reboots in the long term. Only the hot-pluggable ones. > It also lays the ground work for a fully decoupled device model > whereas the only interface between the devices and the outside world > is a subset of QMP (think seccomp()). > > Whether creating a machine with no command line options is high value > is probably irrelevant. I think we want to go in this direction > regardless. I agree it's a good thing.
On 02/27/2011 05:33 AM, Avi Kivity wrote: > On 02/24/2011 07:25 PM, Anthony Liguori wrote: >>> Is it really necessary? What's blocking us from initializing >>> chardevs early? >> >> >> Well.... >> >> We initialize all chardevs at once right now and what set of chardevs >> there are depends on the machine (by the way defaults are applied). >> You could initialize chardevs in two stages although that requires >> quite a bit of additional complexity. > > We could initialize chardevs on demand - that should resolve any > dependencies? I think that potentially screws up the way -global works. There's some deep black magic involved in how -global, defaults, and device initialization interact. >>> >>> It would be a pity to divorce the monitor from chardevs, they're >>> really flexible. >> >> Couple considerations: >> >> 1) chardevs don't support multiple simultaneous connections. I view >> this as a blocker for QMP. > > What do you mean by that? Something like ,server which keeps on > listening after it a connection is established? ,server won't allow multiple simultaneous connections. CharDriverStates simply don't have a connection semantic. There can only be one thing connected to it at a time. This is why we don't use CharDriverState for VNC. We should have another abstraction for connection based backend. I'll take a go at this when I'm ready to try to get those patches in. Just to be clear though, there is a CharDriverState version of the new QMP server. This would be a second option for creating a QMP server and it takes a different command line sytnax. >> 2) Because chardevs don't support multiple connections, we can't >> reasonably hook on things like connect/disconnect which means that >> fd's sent via SCM_RIGHTs have to be handled in a very special way. >> By going outside of the chardev layer, we can let fd's via SCM_RIGHTS >> queue up naturally and have getfd/setfd refer to the fd at the top of >> the queue. It makes it quite a bit easier to work with (I believe >> Daniel had actually requested this a while ago). > > I really don't follow... what's the connection between SCM_RIGHTS and > multiple connections? Monitors have a single fd. That fd is associated with the monitor and lives beyond the length of the connection to the monitor (recall that chardevs don't have a notion of connection life cycle). This means if a management tool forgets to do a closefd on an unused fd, there's no easy way for QEMU to automatically clean that up. IOW, a crashed management tool == fd leak in QEMU. >>>> (6) can be started right now. (1) comes with the QAPI merge. (2) >>>> is pretty easy to do after applying this patch. (3) is probably >>>> something that can be done shortly after (1). (4) and (5) really >>>> require everything but (6) to be in place before we can meaningful >>>> do it. >>>> >>>> I think we can lay out much of the ground work for this in 0.15 and >>>> I think we can have a total conversion realistically for 0.16. >>>> That means that by EOY, we could invoke QEMU with no options and do >>>> everything through QMP. >>> >>> It's something that I've agitated for a long while, but when I see >>> all the work needed, I'm not sure it's cost effective. >> >> There's a lot of secondary benefits that come from doing this. QMP >> becomes a much stronger interface. A lot of operations that right >> now are only specifiable by the command line become dynamic which >> mitigates reboots in the long term. > > Only the hot-pluggable ones. Yup, but it forces us to treat options that cannot change at runtime as special cases which I think is a nice plus. Customers don't like having their guests rebooted during a scheduled downtime so we really ought to try to have as many things tunable at runtime as possible. Regards, Anthony Liguori
On 02/28/2011 06:01 AM, Anthony Liguori wrote: > >>>> >>>> It would be a pity to divorce the monitor from chardevs, they're >>>> really flexible. >>> >>> Couple considerations: >>> >>> 1) chardevs don't support multiple simultaneous connections. I view >>> this as a blocker for QMP. >> >> What do you mean by that? Something like ,server which keeps on >> listening after it a connection is established? > > ,server won't allow multiple simultaneous connections. > CharDriverStates simply don't have a connection semantic. There can > only be one thing connected to it at a time. This is why we don't use > CharDriverState for VNC. I meant an extension to ,server that keeps on listening. > > We should have another abstraction for connection based backend. I'll > take a go at this when I'm ready to try to get those patches in. Shouldn't each new connection return a chardev? > > Just to be clear though, there is a CharDriverState version of the new > QMP server. This would be a second option for creating a QMP server > and it takes a different command line sytnax. > >>> 2) Because chardevs don't support multiple connections, we can't >>> reasonably hook on things like connect/disconnect which means that >>> fd's sent via SCM_RIGHTs have to be handled in a very special way. >>> By going outside of the chardev layer, we can let fd's via >>> SCM_RIGHTS queue up naturally and have getfd/setfd refer to the fd >>> at the top of the queue. It makes it quite a bit easier to work >>> with (I believe Daniel had actually requested this a while ago). >> >> I really don't follow... what's the connection between SCM_RIGHTS and >> multiple connections? > > Monitors have a single fd. That fd is associated with the monitor and > lives beyond the length of the connection to the monitor (recall that > chardevs don't have a notion of connection life cycle). This means if > a management tool forgets to do a closefd on an unused fd, there's no > easy way for QEMU to automatically clean that up. IOW, a crashed > management tool == fd leak in QEMU. I guess we could add a close() event to chardev?
On 02/28/2011 09:20 AM, Avi Kivity wrote: >> >> We should have another abstraction for connection based backend. I'll >> take a go at this when I'm ready to try to get those patches in. > > Shouldn't each new connection return a chardev? You would need a kind of "factory" interface that knows how to create a new {monitor,serial port,you name it} for each new connection. Actually it doesn't make much sense except for monitors. Paolo
On 02/28/2011 10:57 AM, Paolo Bonzini wrote: > On 02/28/2011 09:20 AM, Avi Kivity wrote: >>> >>> We should have another abstraction for connection based backend. I'll >>> take a go at this when I'm ready to try to get those patches in. >> >> Shouldn't each new connection return a chardev? > > You would need a kind of "factory" interface that knows how to create > a new {monitor,serial port,you name it} for each new connection. > Actually it doesn't make much sense except for monitors. Monitors and vnc.
On 02/28/2011 10:13 AM, Avi Kivity wrote: >>> >> >> You would need a kind of "factory" interface that knows how to create >> a new {monitor,serial port,you name it} for each new connection. >> Actually it doesn't make much sense except for monitors. > > Monitors and vnc. True, but vnc is not a chardev and it probably wouldn't make much sense for it to be one. Actually, it may make some sense for virtio-serial... Paolo
On 02/28/2011 03:13 AM, Avi Kivity wrote: > On 02/28/2011 10:57 AM, Paolo Bonzini wrote: >> On 02/28/2011 09:20 AM, Avi Kivity wrote: >>>> >>>> We should have another abstraction for connection based backend. I'll >>>> take a go at this when I'm ready to try to get those patches in. >>> >>> Shouldn't each new connection return a chardev? >> >> You would need a kind of "factory" interface that knows how to create >> a new {monitor,serial port,you name it} for each new connection. >> Actually it doesn't make much sense except for monitors. > > Monitors and vnc. VNC also does it's own buffering when reading and writing to a file descriptor. The chardev layer doesn't really have a concept of flow control. Regards, Anthony Liguori
diff --git a/vl.c b/vl.c index b436952..181cc77 100644 --- a/vl.c +++ b/vl.c @@ -1917,17 +1917,360 @@ static const QEMUOption *lookup_opt(int argc, char **argv, return popt; } +static int qemu_machine_init(QEMUMachine *machine, const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *boot_devices, const char *cpu_model, + int snapshot, int tb_size, const char *gdbstub_dev, + const char *loadvm, const char *incoming) +{ + DisplayState *ds; + DisplayChangeListener *dcl; + int i; + int linux_boot; + int show_vnc_port = 0; + + /* + * Default to max_cpus = smp_cpus, in case the user doesn't + * specify a max_cpus value. + */ + if (!max_cpus) + max_cpus = smp_cpus; + + machine->max_cpus = machine->max_cpus ?: 1; /* Default to UP */ + if (smp_cpus > machine->max_cpus) { + fprintf(stderr, "Number of SMP cpus requested (%d), exceeds max cpus " + "supported by machine `%s' (%d)\n", smp_cpus, machine->name, + machine->max_cpus); + return 1; + } + + qemu_opts_foreach(qemu_find_opts("device"), default_driver_check, NULL, 0); + qemu_opts_foreach(qemu_find_opts("global"), default_driver_check, NULL, 0); + + if (machine->no_serial) { + default_serial = 0; + } + if (machine->no_parallel) { + default_parallel = 0; + } + if (!machine->use_virtcon) { + default_virtcon = 0; + } + if (machine->no_vga) { + default_vga = 0; + } + if (machine->no_floppy) { + default_floppy = 0; + } + if (machine->no_cdrom) { + default_cdrom = 0; + } + if (machine->no_sdcard) { + default_sdcard = 0; + } + + if (display_type == DT_NOGRAPHIC) { + if (default_parallel) + add_device_config(DEV_PARALLEL, "null"); + if (default_serial && default_monitor) { + add_device_config(DEV_SERIAL, "mon:stdio"); + } else if (default_virtcon && default_monitor) { + add_device_config(DEV_VIRTCON, "mon:stdio"); + } else { + if (default_serial) + add_device_config(DEV_SERIAL, "stdio"); + if (default_virtcon) + add_device_config(DEV_VIRTCON, "stdio"); + if (default_monitor) + monitor_parse("stdio", "readline"); + } + } else { + if (default_serial) + add_device_config(DEV_SERIAL, "vc:80Cx24C"); + if (default_parallel) + add_device_config(DEV_PARALLEL, "vc:80Cx24C"); + if (default_monitor) + monitor_parse("vc:80Cx24C", "readline"); + if (default_virtcon) + add_device_config(DEV_VIRTCON, "vc:80Cx24C"); + } + if (default_vga) + vga_interface_type = VGA_CIRRUS; + + if (qemu_opts_foreach(qemu_find_opts("chardev"), chardev_init_func, NULL, 1) != 0) + exit(1); +#ifdef CONFIG_VIRTFS + if (qemu_opts_foreach(qemu_find_opts("fsdev"), fsdev_init_func, NULL, 1) != 0) { + return 1; + } +#endif + + if (kvm_allowed) { + int ret = kvm_init(); + if (ret < 0) { + if (!kvm_available()) { + printf("KVM not supported for this target\n"); + } else { + fprintf(stderr, "failed to initialize KVM: %s\n", strerror(-ret)); + } + return 1; + } + } + + linux_boot = (kernel_filename != NULL); + + if (!linux_boot && *kernel_cmdline != '\0') { + fprintf(stderr, "-append only allowed with -kernel option\n"); + return 1; + } + + if (!linux_boot && initrd_filename != NULL) { + fprintf(stderr, "-initrd only allowed with -kernel option\n"); + return 1; + } + + if (net_init_clients() < 0) { + return 1; + } + + /* init the bluetooth world */ + if (foreach_device_config(DEV_BT, bt_parse)) + return 1; + + /* init the memory */ + if (ram_size == 0) + ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; + + /* init the dynamic translator */ + cpu_exec_init_all(tb_size * 1024 * 1024); + + /* open the virtual block devices */ + if (snapshot) + qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot, NULL, 0); + if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func, &machine->use_scsi, 1) != 0) + return 1; + + default_drive(default_cdrom, snapshot, machine->use_scsi, + IF_DEFAULT, 2, CDROM_OPTS); + default_drive(default_floppy, snapshot, machine->use_scsi, + IF_FLOPPY, 0, FD_OPTS); + default_drive(default_sdcard, snapshot, machine->use_scsi, + IF_SD, 0, SD_OPTS); + + register_savevm_live(NULL, "ram", 0, 4, NULL, ram_save_live, NULL, + ram_load, NULL); + + if (nb_numa_nodes > 0) { + int i; + + if (nb_numa_nodes > smp_cpus) { + nb_numa_nodes = smp_cpus; + } + + /* If no memory size if given for any node, assume the default case + * and distribute the available memory equally across all nodes + */ + for (i = 0; i < nb_numa_nodes; i++) { + if (node_mem[i] != 0) + break; + } + if (i == nb_numa_nodes) { + uint64_t usedmem = 0; + + /* On Linux, the each node's border has to be 8MB aligned, + * the final node gets the rest. + */ + for (i = 0; i < nb_numa_nodes - 1; i++) { + node_mem[i] = (ram_size / nb_numa_nodes) & ~((1 << 23UL) - 1); + usedmem += node_mem[i]; + } + node_mem[i] = ram_size - usedmem; + } + + for (i = 0; i < nb_numa_nodes; i++) { + if (node_cpumask[i] != 0) + break; + } + /* assigning the VCPUs round-robin is easier to implement, guest OSes + * must cope with this anyway, because there are BIOSes out there in + * real machines which also use this scheme. + */ + if (i == nb_numa_nodes) { + for (i = 0; i < smp_cpus; i++) { + node_cpumask[i % nb_numa_nodes] |= 1 << i; + } + } + } + + if (qemu_opts_foreach(qemu_find_opts("mon"), mon_init_func, NULL, 1) != 0) { + return 1; + } + + if (foreach_device_config(DEV_SERIAL, serial_parse) < 0) + return 1; + if (foreach_device_config(DEV_PARALLEL, parallel_parse) < 0) + return 1; + if (foreach_device_config(DEV_VIRTCON, virtcon_parse) < 0) + return 1; + if (foreach_device_config(DEV_DEBUGCON, debugcon_parse) < 0) + return 1; + + module_call_init(MODULE_INIT_DEVICE); + + if (qemu_opts_foreach(qemu_find_opts("device"), device_help_func, NULL, 0) != 0) + return 1; + + if (watchdog) { + i = select_watchdog(watchdog); + if (i > 0) + exit (i == 1 ? 1 : 0); + } + + if (machine->compat_props) { + qdev_prop_register_global_list(machine->compat_props); + } + qemu_add_globals(); + + machine->init(ram_size, boot_devices, + kernel_filename, kernel_cmdline, initrd_filename, cpu_model); + + cpu_synchronize_all_post_init(); + + set_numa_modes(); + + current_machine = machine; + + /* init USB devices */ + if (usb_enabled) { + if (foreach_device_config(DEV_USB, usb_parse) < 0) + return 1; + } + + /* init generic devices */ + if (qemu_opts_foreach(qemu_find_opts("device"), device_init_func, NULL, 1) != 0) + return 1; + + net_check_clients(); + + /* just use the first displaystate for the moment */ + ds = get_displaystate(); + + if (using_spice) + display_remote++; + if (display_type == DT_DEFAULT && !display_remote) { +#if defined(CONFIG_SDL) || defined(CONFIG_COCOA) + display_type = DT_SDL; +#else + vnc_display = "localhost:0,to=99"; + show_vnc_port = 1; +#endif + } + + + /* init local displays */ + switch (display_type) { + case DT_NOGRAPHIC: + break; +#if defined(CONFIG_CURSES) + case DT_CURSES: + curses_display_init(ds, full_screen); + break; +#endif +#if defined(CONFIG_SDL) + case DT_SDL: + sdl_display_init(ds, full_screen, no_frame); + break; +#elif defined(CONFIG_COCOA) + case DT_SDL: + cocoa_display_init(ds, full_screen); + break; +#endif + default: + break; + } + + /* init remote displays */ + if (vnc_display) { + vnc_display_init(ds); + if (vnc_display_open(ds, vnc_display) < 0) + return 1; + + if (show_vnc_port) { + printf("VNC server running on `%s'\n", vnc_display_local_addr(ds)); + } + } +#ifdef CONFIG_SPICE + if (using_spice && !qxl_enabled) { + qemu_spice_display_init(ds); + } +#endif + + /* display setup */ + dpy_resize(ds); + dcl = ds->listeners; + while (dcl != NULL) { + if (dcl->dpy_refresh != NULL) { + ds->gui_timer = qemu_new_timer(rt_clock, gui_update, ds); + qemu_mod_timer(ds->gui_timer, qemu_get_clock(rt_clock)); + break; + } + dcl = dcl->next; + } + if (ds->gui_timer == NULL) { + nographic_timer = qemu_new_timer(rt_clock, nographic_update, NULL); + qemu_mod_timer(nographic_timer, qemu_get_clock(rt_clock)); + } + text_consoles_set_display(ds); + + if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) { + fprintf(stderr, "qemu: could not open gdbserver on device '%s'\n", + gdbstub_dev); + return 1; + } + + qdev_machine_creation_done(); + + if (rom_load_all() != 0) { + fprintf(stderr, "rom loading failed\n"); + return 1; + } + + /* TODO: once all bus devices are qdevified, this should be done + * when bus is created by qdev.c */ + qemu_register_reset(qbus_reset_all_fn, sysbus_get_default()); + qemu_run_machine_init_done_notifiers(); + + qemu_system_reset(); + if (loadvm) { + if (load_vmstate(loadvm) < 0) { + autostart = 0; + } + } + + if (incoming) { + int ret = qemu_start_incoming_migration(incoming); + if (ret < 0) { + fprintf(stderr, "Migration failed. Exit code %s(%d), exiting.\n", + incoming, ret); + return ret; + } + } else if (autostart) { + vm_start(); + } + + return 0; +} + int main(int argc, char **argv, char **envp) { const char *gdbstub_dev = NULL; int i; - int snapshot, linux_boot; + int snapshot; const char *icount_option = NULL; const char *initrd_filename; const char *kernel_filename, *kernel_cmdline; char boot_devices[33] = "cad"; /* default to HD->floppy->CD-ROM */ - DisplayState *ds; - DisplayChangeListener *dcl; int cyls, heads, secs, translation; QemuOpts *hda_opts = NULL, *opts; QemuOptsList *olist; @@ -1939,8 +2282,8 @@ int main(int argc, char **argv, char **envp) int tb_size; const char *pid_file = NULL; const char *incoming = NULL; - int show_vnc_port = 0; int defconfig = 1; + int ret; #ifdef CONFIG_SIMPLE_TRACE const char *trace_file = NULL; @@ -2786,84 +3129,9 @@ int main(int argc, char **argv, char **envp) */ st_set_trace_file(trace_file); #endif - /* - * Default to max_cpus = smp_cpus, in case the user doesn't - * specify a max_cpus value. - */ - if (!max_cpus) - max_cpus = smp_cpus; - - machine->max_cpus = machine->max_cpus ?: 1; /* Default to UP */ - if (smp_cpus > machine->max_cpus) { - fprintf(stderr, "Number of SMP cpus requested (%d), exceeds max cpus " - "supported by machine `%s' (%d)\n", smp_cpus, machine->name, - machine->max_cpus); - exit(1); - } - - qemu_opts_foreach(qemu_find_opts("device"), default_driver_check, NULL, 0); - qemu_opts_foreach(qemu_find_opts("global"), default_driver_check, NULL, 0); - - if (machine->no_serial) { - default_serial = 0; - } - if (machine->no_parallel) { - default_parallel = 0; - } - if (!machine->use_virtcon) { - default_virtcon = 0; - } - if (machine->no_vga) { - default_vga = 0; - } - if (machine->no_floppy) { - default_floppy = 0; - } - if (machine->no_cdrom) { - default_cdrom = 0; - } - if (machine->no_sdcard) { - default_sdcard = 0; - } - - if (display_type == DT_NOGRAPHIC) { - if (default_parallel) - add_device_config(DEV_PARALLEL, "null"); - if (default_serial && default_monitor) { - add_device_config(DEV_SERIAL, "mon:stdio"); - } else if (default_virtcon && default_monitor) { - add_device_config(DEV_VIRTCON, "mon:stdio"); - } else { - if (default_serial) - add_device_config(DEV_SERIAL, "stdio"); - if (default_virtcon) - add_device_config(DEV_VIRTCON, "stdio"); - if (default_monitor) - monitor_parse("stdio", "readline"); - } - } else { - if (default_serial) - add_device_config(DEV_SERIAL, "vc:80Cx24C"); - if (default_parallel) - add_device_config(DEV_PARALLEL, "vc:80Cx24C"); - if (default_monitor) - monitor_parse("vc:80Cx24C", "readline"); - if (default_virtcon) - add_device_config(DEV_VIRTCON, "vc:80Cx24C"); - } - if (default_vga) - vga_interface_type = VGA_CIRRUS; socket_init(); - if (qemu_opts_foreach(qemu_find_opts("chardev"), chardev_init_func, NULL, 1) != 0) - exit(1); -#ifdef CONFIG_VIRTFS - if (qemu_opts_foreach(qemu_find_opts("fsdev"), fsdev_init_func, NULL, 1) != 0) { - exit(1); - } -#endif - os_daemonize(); if (pid_file && qemu_create_pidfile(pid_file) != 0) { @@ -2871,33 +3139,10 @@ int main(int argc, char **argv, char **envp) exit(1); } - if (kvm_allowed) { - int ret = kvm_init(); - if (ret < 0) { - if (!kvm_available()) { - printf("KVM not supported for this target\n"); - } else { - fprintf(stderr, "failed to initialize KVM: %s\n", strerror(-ret)); - } - exit(1); - } - } - if (qemu_init_main_loop()) { fprintf(stderr, "qemu_init_main_loop failed\n"); exit(1); } - linux_boot = (kernel_filename != NULL); - - if (!linux_boot && *kernel_cmdline != '\0') { - fprintf(stderr, "-append only allowed with -kernel option\n"); - exit(1); - } - - if (!linux_boot && initrd_filename != NULL) { - fprintf(stderr, "-initrd only allowed with -kernel option\n"); - exit(1); - } os_set_line_buffering(); @@ -2907,244 +3152,22 @@ int main(int argc, char **argv, char **envp) } configure_icount(icount_option); - if (net_init_clients() < 0) { - exit(1); - } - - /* init the bluetooth world */ - if (foreach_device_config(DEV_BT, bt_parse)) - exit(1); - - /* init the memory */ - if (ram_size == 0) - ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; - - /* init the dynamic translator */ - cpu_exec_init_all(tb_size * 1024 * 1024); - bdrv_init_with_whitelist(); blk_mig_init(); - /* open the virtual block devices */ - if (snapshot) - qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot, NULL, 0); - if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func, &machine->use_scsi, 1) != 0) - exit(1); - - default_drive(default_cdrom, snapshot, machine->use_scsi, - IF_DEFAULT, 2, CDROM_OPTS); - default_drive(default_floppy, snapshot, machine->use_scsi, - IF_FLOPPY, 0, FD_OPTS); - default_drive(default_sdcard, snapshot, machine->use_scsi, - IF_SD, 0, SD_OPTS); - - register_savevm_live(NULL, "ram", 0, 4, NULL, ram_save_live, NULL, - ram_load, NULL); - - if (nb_numa_nodes > 0) { - int i; - - if (nb_numa_nodes > smp_cpus) { - nb_numa_nodes = smp_cpus; - } - - /* If no memory size if given for any node, assume the default case - * and distribute the available memory equally across all nodes - */ - for (i = 0; i < nb_numa_nodes; i++) { - if (node_mem[i] != 0) - break; - } - if (i == nb_numa_nodes) { - uint64_t usedmem = 0; - - /* On Linux, the each node's border has to be 8MB aligned, - * the final node gets the rest. - */ - for (i = 0; i < nb_numa_nodes - 1; i++) { - node_mem[i] = (ram_size / nb_numa_nodes) & ~((1 << 23UL) - 1); - usedmem += node_mem[i]; - } - node_mem[i] = ram_size - usedmem; - } - - for (i = 0; i < nb_numa_nodes; i++) { - if (node_cpumask[i] != 0) - break; - } - /* assigning the VCPUs round-robin is easier to implement, guest OSes - * must cope with this anyway, because there are BIOSes out there in - * real machines which also use this scheme. - */ - if (i == nb_numa_nodes) { - for (i = 0; i < smp_cpus; i++) { - node_cpumask[i % nb_numa_nodes] |= 1 << i; - } - } - } - - if (qemu_opts_foreach(qemu_find_opts("mon"), mon_init_func, NULL, 1) != 0) { - exit(1); - } - - if (foreach_device_config(DEV_SERIAL, serial_parse) < 0) - exit(1); - if (foreach_device_config(DEV_PARALLEL, parallel_parse) < 0) - exit(1); - if (foreach_device_config(DEV_VIRTCON, virtcon_parse) < 0) - exit(1); - if (foreach_device_config(DEV_DEBUGCON, debugcon_parse) < 0) - exit(1); - - module_call_init(MODULE_INIT_DEVICE); - - if (qemu_opts_foreach(qemu_find_opts("device"), device_help_func, NULL, 0) != 0) - exit(0); - - if (watchdog) { - i = select_watchdog(watchdog); - if (i > 0) - exit (i == 1 ? 1 : 0); - } - - if (machine->compat_props) { - qdev_prop_register_global_list(machine->compat_props); - } - qemu_add_globals(); - - machine->init(ram_size, boot_devices, - kernel_filename, kernel_cmdline, initrd_filename, cpu_model); - - cpu_synchronize_all_post_init(); - /* must be after terminal init, SDL library changes signal handlers */ os_setup_signal_handling(); - set_numa_modes(); - - current_machine = machine; - - /* init USB devices */ - if (usb_enabled) { - if (foreach_device_config(DEV_USB, usb_parse) < 0) - exit(1); - } - - /* init generic devices */ - if (qemu_opts_foreach(qemu_find_opts("device"), device_init_func, NULL, 1) != 0) - exit(1); - - net_check_clients(); - - /* just use the first displaystate for the moment */ - ds = get_displaystate(); - - if (using_spice) - display_remote++; - if (display_type == DT_DEFAULT && !display_remote) { -#if defined(CONFIG_SDL) || defined(CONFIG_COCOA) - display_type = DT_SDL; -#else - vnc_display = "localhost:0,to=99"; - show_vnc_port = 1; -#endif - } - - - /* init local displays */ - switch (display_type) { - case DT_NOGRAPHIC: - break; -#if defined(CONFIG_CURSES) - case DT_CURSES: - curses_display_init(ds, full_screen); - break; -#endif -#if defined(CONFIG_SDL) - case DT_SDL: - sdl_display_init(ds, full_screen, no_frame); - break; -#elif defined(CONFIG_COCOA) - case DT_SDL: - cocoa_display_init(ds, full_screen); - break; -#endif - default: - break; - } - - /* init remote displays */ - if (vnc_display) { - vnc_display_init(ds); - if (vnc_display_open(ds, vnc_display) < 0) - exit(1); - - if (show_vnc_port) { - printf("VNC server running on `%s'\n", vnc_display_local_addr(ds)); - } - } -#ifdef CONFIG_SPICE - if (using_spice && !qxl_enabled) { - qemu_spice_display_init(ds); - } -#endif - - /* display setup */ - dpy_resize(ds); - dcl = ds->listeners; - while (dcl != NULL) { - if (dcl->dpy_refresh != NULL) { - ds->gui_timer = qemu_new_timer(rt_clock, gui_update, ds); - qemu_mod_timer(ds->gui_timer, qemu_get_clock(rt_clock)); - break; - } - dcl = dcl->next; - } - if (ds->gui_timer == NULL) { - nographic_timer = qemu_new_timer(rt_clock, nographic_update, NULL); - qemu_mod_timer(nographic_timer, qemu_get_clock(rt_clock)); - } - text_consoles_set_display(ds); - - if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) { - fprintf(stderr, "qemu: could not open gdbserver on device '%s'\n", - gdbstub_dev); - exit(1); - } - - qdev_machine_creation_done(); - - if (rom_load_all() != 0) { - fprintf(stderr, "rom loading failed\n"); - exit(1); - } - - /* TODO: once all bus devices are qdevified, this should be done - * when bus is created by qdev.c */ - qemu_register_reset(qbus_reset_all_fn, sysbus_get_default()); - qemu_run_machine_init_done_notifiers(); - - qemu_system_reset(); - if (loadvm) { - if (load_vmstate(loadvm) < 0) { - autostart = 0; - } - } + os_setup_post(); - if (incoming) { - int ret = qemu_start_incoming_migration(incoming); - if (ret < 0) { - fprintf(stderr, "Migration failed. Exit code %s(%d), exiting.\n", - incoming, ret); - exit(ret); - } - } else if (autostart) { - vm_start(); + ret = qemu_machine_init(machine, kernel_filename, kernel_cmdline, + initrd_filename, boot_devices, cpu_model, snapshot, + tb_size, gdbstub_dev, loadvm, incoming); + if (ret) { + exit(ret); } - os_setup_post(); - main_loop(); quit_timers(); net_cleanup();
The goal is to enable the monitor to run independently of whether the machine has been created such that the monitor can be used to specify all of the parameters for machine initialization. Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>