diff mbox

[SEABIOS] Move qemu config port access functions into separate file.

Message ID 20090914125141.GB30746@redhat.com
State Superseded
Headers show

Commit Message

Gleb Natapov Sept. 14, 2009, 12:51 p.m. UTC
Move qemu config code from smbios.c to its own files. Add support for
-boot menu=on|off qemu option.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
--
			Gleb.

Comments

Kevin O'Connor Sept. 15, 2009, 12:08 a.m. UTC | #1
On Mon, Sep 14, 2009 at 03:51:41PM +0300, Gleb Natapov wrote:
> Move qemu config code from smbios.c to its own files. Add support for
> -boot menu=on|off qemu option.

Hi Gleb,

A couple of comments:

>      // Allow user to modify BCV/IPL order.
> -    interactive_bootmenu();
> +    if (qemu_cfg_show_boot_menu())
> +        interactive_bootmenu();

Can you move this test into interactive_bootmenu()?  (For non-qemu
users the flow control looks odd otherwise.)

> --- /dev/null
> +++ b/src/pv.c

What is "pv"?  How about "qemu-cfg.c"?

> +void qemu_cfg_port_probe(void)
> +{
> +    char *sig = "QEMU";
> +    int i;
> +
> +    qemu_cfg_present = 1;
> +
> +    qemu_cfg_select(QEMU_CFG_SIGNATURE);
> +
> +    for (i = 0; i < 4; i++)
> +        if (inb(QEMU_CFG_DATA_PORT) != sig[i]) {
> +            qemu_cfg_present = 0;
> +            break;
> +        }
> +    dprintf(4, "qemu_cfg_present=%d\n", qemu_cfg_present);
> +}

This needs to have a "if (! CONFIG_COREBOOT) return;" - as the current
check for qemu is not safe on real hardware.

Otherwise it looks good to me.

As an aside, it would be good to have a conversation on general BIOS
configuration options.  These types of settings are going to be useful
on real hardware also - it would be nice to come up with a scheme that
would work on qemu and coreboot.  Maybe something like
get_config_u32("ShowBootMenu") - where on qemu it would get the info
from the qemu port but on coreboot it would pull the setting from the
coreboot flash filesystem.

Thanks,
-Kevin
Gleb Natapov Sept. 15, 2009, 5:43 a.m. UTC | #2
On Mon, Sep 14, 2009 at 08:08:24PM -0400, Kevin O'Connor wrote:
> On Mon, Sep 14, 2009 at 03:51:41PM +0300, Gleb Natapov wrote:
> > Move qemu config code from smbios.c to its own files. Add support for
> > -boot menu=on|off qemu option.
> 
> Hi Gleb,
> 
> A couple of comments:
> 
> >      // Allow user to modify BCV/IPL order.
> > -    interactive_bootmenu();
> > +    if (qemu_cfg_show_boot_menu())
> > +        interactive_bootmenu();
> 
> Can you move this test into interactive_bootmenu()?  (For non-qemu
> users the flow control looks odd otherwise.)
> 
OK. The flow control will not go away though just move to other place so
non-qemu user will see odd flow control anyway :)

> > --- /dev/null
> > +++ b/src/pv.c
> 
> What is "pv"?  How about "qemu-cfg.c"?
> 
pv == ParaVirtualization. I want to put non qemu specific thing there
to. For instance I put kvm_para_available() function there that checks
cpuid signature. I want to use it to replace if(CONFIG_KVM) in
ram_probe().

> > +void qemu_cfg_port_probe(void)
> > +{
> > +    char *sig = "QEMU";
> > +    int i;
> > +
> > +    qemu_cfg_present = 1;
> > +
> > +    qemu_cfg_select(QEMU_CFG_SIGNATURE);
> > +
> > +    for (i = 0; i < 4; i++)
> > +        if (inb(QEMU_CFG_DATA_PORT) != sig[i]) {
> > +            qemu_cfg_present = 0;
> > +            break;
> > +        }
> > +    dprintf(4, "qemu_cfg_present=%d\n", qemu_cfg_present);
> > +}
> 
> This needs to have a "if (! CONFIG_COREBOOT) return;" - as the current
> check for qemu is not safe on real hardware.
> 
Will add.

> Otherwise it looks good to me.
> 
> As an aside, it would be good to have a conversation on general BIOS
> configuration options.  These types of settings are going to be useful
> on real hardware also - it would be nice to come up with a scheme that
> would work on qemu and coreboot.  Maybe something like
> get_config_u32("ShowBootMenu") - where on qemu it would get the info
> from the qemu port but on coreboot it would pull the setting from the
> coreboot flash filesystem.
> 
Lets have conversation now. Sounds useful to me. Do you want to use
strings as option names though? They add to BIOS image size and it is
limited, no?

--
			Gleb.
Kevin O'Connor Sept. 16, 2009, 2:02 a.m. UTC | #3
On Tue, Sep 15, 2009 at 08:43:39AM +0300, Gleb Natapov wrote:
> On Mon, Sep 14, 2009 at 08:08:24PM -0400, Kevin O'Connor wrote:
> > As an aside, it would be good to have a conversation on general BIOS
> > configuration options.  These types of settings are going to be useful
> > on real hardware also - it would be nice to come up with a scheme that
> > would work on qemu and coreboot.  Maybe something like
> > get_config_u32("ShowBootMenu") - where on qemu it would get the info
> > from the qemu port but on coreboot it would pull the setting from the
> > coreboot flash filesystem.
> > 
> Lets have conversation now. Sounds useful to me. Do you want to use
> strings as option names though? They add to BIOS image size and it is
> limited, no?

My preference is strings - I think the long-term flexibility they
provide is worth the slight additional overhead they require.

Currently, SeaBIOS is just under 64K -- if features continue to get
added (eg, usb keyboard/boot) then it will likely creep into the
e-segment.  I don't foresee any hard limits on space coming up.

-Kevin
Gleb Natapov Sept. 17, 2009, 9:57 a.m. UTC | #4
On Tue, Sep 15, 2009 at 10:02:59PM -0400, Kevin O'Connor wrote:
> On Tue, Sep 15, 2009 at 08:43:39AM +0300, Gleb Natapov wrote:
> > On Mon, Sep 14, 2009 at 08:08:24PM -0400, Kevin O'Connor wrote:
> > > As an aside, it would be good to have a conversation on general BIOS
> > > configuration options.  These types of settings are going to be useful
> > > on real hardware also - it would be nice to come up with a scheme that
> > > would work on qemu and coreboot.  Maybe something like
> > > get_config_u32("ShowBootMenu") - where on qemu it would get the info
> > > from the qemu port but on coreboot it would pull the setting from the
> > > coreboot flash filesystem.
> > > 
> > Lets have conversation now. Sounds useful to me. Do you want to use
> > strings as option names though? They add to BIOS image size and it is
> > limited, no?
> 
> My preference is strings - I think the long-term flexibility they
> provide is worth the slight additional overhead they require.
> 
> Currently, SeaBIOS is just under 64K -- if features continue to get
> added (eg, usb keyboard/boot) then it will likely creep into the
> e-segment.  I don't foresee any hard limits on space coming up.
> 
Fine by me.

The configuration interface should be able to read streams of data
though.  Qemu uses it to pass additional ACPI tables for instance. So
it not just simple key->value interface. get_config_u32("ShowBootMenu")
will work for simple cases but how can we express stream semantic? May be:

table_count = get_config_u16("AdditionalAcpiCount")
select_config("AdditionalAcpiTables");
for (i=0; i<table_count; i++) {
   len = config_read(table[i], table_len[i]);
}

--
			Gleb.
Kevin O'Connor Sept. 18, 2009, 1:24 a.m. UTC | #5
On Thu, Sep 17, 2009 at 12:57:28PM +0300, Gleb Natapov wrote:
> The configuration interface should be able to read streams of data
> though.  Qemu uses it to pass additional ACPI tables for instance. So
> it not just simple key->value interface. get_config_u32("ShowBootMenu")
> will work for simple cases but how can we express stream semantic? May be:
> 
> table_count = get_config_u16("AdditionalAcpiCount")
> select_config("AdditionalAcpiTables");
> for (i=0; i<table_count; i++) {
>    len = config_read(table[i], table_len[i]);
> }

On coreboot there is the Coreboot FileSystem (CBFS).  Basically, the
flash stores a series of named files, and SeaBIOS knows how to iterate
through them.  So, for instance, one might find the file
"pci1013,00b8.rom" which contains an option rom for pci device
1013:00b8, or one might find "floppyimg/FreeDOS" with an image of a
floppy to be emulated.

So, ideally qemu would do something similar.  Maybe something like:
copy_config_file("AdditionalAcpiTables", destfileptr, destfilemaxlen).
The exact mechanism for extracting the info is flexible.  To be
compatible with the CBFS interface, seabios just needs a way to "walk"
the list of files, find out how big a given file is, and be able to
copy the file to ram.

If anyone is curious, the cbfs functions are in src/coreboot.c - the
main interface is:

// Find the file with the given filename.
struct cbfs_file *cbfs_findfile(const char *fname)
// Find next file with the given filename prefix.
struct cbfs_file *cbfs_findprefix(const char *prefix, struct cbfs_file *last)
// Determine the uncompressed size of a datafile.
u32 cbfs_datasize(struct cbfs_file *file)
// Copy a file to memory (uncompressing if necessary)
int cbfs_copyfile(struct cbfs_file *file, void *dst, u32 maxlen)

-Kevin
Gleb Natapov Sept. 18, 2009, 10:01 a.m. UTC | #6
On Thu, Sep 17, 2009 at 09:24:11PM -0400, Kevin O'Connor wrote:
> On Thu, Sep 17, 2009 at 12:57:28PM +0300, Gleb Natapov wrote:
> > The configuration interface should be able to read streams of data
> > though.  Qemu uses it to pass additional ACPI tables for instance. So
> > it not just simple key->value interface. get_config_u32("ShowBootMenu")
> > will work for simple cases but how can we express stream semantic? May be:
> > 
> > table_count = get_config_u16("AdditionalAcpiCount")
> > select_config("AdditionalAcpiTables");
> > for (i=0; i<table_count; i++) {
> >    len = config_read(table[i], table_len[i]);
> > }
> 
> On coreboot there is the Coreboot FileSystem (CBFS).  Basically, the
> flash stores a series of named files, and SeaBIOS knows how to iterate
> through them.  So, for instance, one might find the file
> "pci1013,00b8.rom" which contains an option rom for pci device
> 1013:00b8, or one might find "floppyimg/FreeDOS" with an image of a
> floppy to be emulated.
> 
> So, ideally qemu would do something similar.  Maybe something like:
Qemu already does something different. For instance acpi tables are
transfered as stream formated like this:
<table count><1 table length><table data><2 table length><table data>
...<n table length><table data>

I don't think qemu should expose file system API to a BIOS.

> copy_config_file("AdditionalAcpiTables", destfileptr, destfilemaxlen).
> The exact mechanism for extracting the info is flexible.  To be
> compatible with the CBFS interface, seabios just needs a way to "walk"
> the list of files, find out how big a given file is, and be able to
> copy the file to ram.
> 
> If anyone is curious, the cbfs functions are in src/coreboot.c - the
> main interface is:
> 
> // Find the file with the given filename.
> struct cbfs_file *cbfs_findfile(const char *fname)
> // Find next file with the given filename prefix.
> struct cbfs_file *cbfs_findprefix(const char *prefix, struct cbfs_file *last)
> // Determine the uncompressed size of a datafile.
> u32 cbfs_datasize(struct cbfs_file *file)
> // Copy a file to memory (uncompressing if necessary)
> int cbfs_copyfile(struct cbfs_file *file, void *dst, u32 maxlen)
> 
> -Kevin

--
			Gleb.
Kevin O'Connor Sept. 19, 2009, 3:16 p.m. UTC | #7
On Fri, Sep 18, 2009 at 01:01:20PM +0300, Gleb Natapov wrote:
> On Thu, Sep 17, 2009 at 09:24:11PM -0400, Kevin O'Connor wrote:
> > On coreboot there is the Coreboot FileSystem (CBFS).  Basically, the
> > flash stores a series of named files, and SeaBIOS knows how to iterate
> > through them.  So, for instance, one might find the file
> > "pci1013,00b8.rom" which contains an option rom for pci device
> > 1013:00b8, or one might find "floppyimg/FreeDOS" with an image of a
> > floppy to be emulated.
> > 
> > So, ideally qemu would do something similar.  Maybe something like:
> Qemu already does something different. For instance acpi tables are
> transfered as stream formated like this:
> <table count><1 table length><table data><2 table length><table data>
> ...<n table length><table data>

Maybe a stream could be introduced with something like:
<name><len><data> <name2><len2><data2> ...

> I don't think qemu should expose file system API to a BIOS.

To be clear, I'm not proposing exposing the system's filesystem to the
guest.

It's really just a way of getting name=value pairs.  If there is a
different way to do this then that's fine.  Ideally, to fit with
SeaBIOS' current code, there would be a way to obtain the size and
data for a given "name" along with an ability to iterate through the
list of "names" available.

-Kevin
Gleb Natapov Sept. 19, 2009, 5:56 p.m. UTC | #8
On Sat, Sep 19, 2009 at 11:16:41AM -0400, Kevin O'Connor wrote:
> On Fri, Sep 18, 2009 at 01:01:20PM +0300, Gleb Natapov wrote:
> > On Thu, Sep 17, 2009 at 09:24:11PM -0400, Kevin O'Connor wrote:
> > > On coreboot there is the Coreboot FileSystem (CBFS).  Basically, the
> > > flash stores a series of named files, and SeaBIOS knows how to iterate
> > > through them.  So, for instance, one might find the file
> > > "pci1013,00b8.rom" which contains an option rom for pci device
> > > 1013:00b8, or one might find "floppyimg/FreeDOS" with an image of a
> > > floppy to be emulated.
> > > 
> > > So, ideally qemu would do something similar.  Maybe something like:
> > Qemu already does something different. For instance acpi tables are
> > transfered as stream formated like this:
> > <table count><1 table length><table data><2 table length><table data>
> > ...<n table length><table data>
> 
> Maybe a stream could be introduced with something like:
> <name><len><data> <name2><len2><data2> ...
> 
The format is already set. The are two ports. You write option id in
first port and you read option value from second one. The value format
is different for each option. Additional acpi table format is like I
described above. If we want to use the same APIs for config access for
coreboot and qemu the API will have to be general enough to accommodate
both approaches. Changing formats is not an option at this stage.

> > I don't think qemu should expose file system API to a BIOS.
> 
> To be clear, I'm not proposing exposing the system's filesystem to the
> guest.
> 
> It's really just a way of getting name=value pairs.  If there is a
> different way to do this then that's fine.  Ideally, to fit with
> SeaBIOS' current code, there would be a way to obtain the size and
> data for a given "name" along with an ability to iterate through the
> list of "names" available.
> 
You can obtain size for acpi tables by reading the whole data first time
just for calculating the data size and discarding the data. But I don't see
the point of doing it. The format was specifically designed to allow
reading one table at a time and placing it in its final place in memory.

--
			Gleb.
Kevin O'Connor Sept. 30, 2009, 1:09 a.m. UTC | #9
On Sat, Sep 19, 2009 at 08:56:55PM +0300, Gleb Natapov wrote:
> On Sat, Sep 19, 2009 at 11:16:41AM -0400, Kevin O'Connor wrote:
> > Maybe a stream could be introduced with something like:
> > <name><len><data> <name2><len2><data2> ...
> > 
> The format is already set. The are two ports. You write option id in
> first port and you read option value from second one. The value format
> is different for each option. Additional acpi table format is like I
> described above. If we want to use the same APIs for config access for
> coreboot and qemu the API will have to be general enough to accommodate
> both approaches. Changing formats is not an option at this stage.

Okay - it doesn't sound like there is much overlap here between qemu
and coreboot.  On coreboot cbfs is used for pulling out option roms,
executables, and floppy images - none of which have much use under
qemu anyway.

So, maybe we should just go back to the discussion of a config
interface.  I think it would be nice to have one api for getting
config items for both qemu and coreboot - something like
get_config_u32("ShowBootMenu").  On coreboot that info could then be
extracted from cbfs and qemu can get in from the "cfg port".

Does that make sense?

-Kevin
Gleb Natapov Sept. 30, 2009, 6:35 a.m. UTC | #10
On Tue, Sep 29, 2009 at 09:09:46PM -0400, Kevin O'Connor wrote:
> On Sat, Sep 19, 2009 at 08:56:55PM +0300, Gleb Natapov wrote:
> > On Sat, Sep 19, 2009 at 11:16:41AM -0400, Kevin O'Connor wrote:
> > > Maybe a stream could be introduced with something like:
> > > <name><len><data> <name2><len2><data2> ...
> > > 
> > The format is already set. The are two ports. You write option id in
> > first port and you read option value from second one. The value format
> > is different for each option. Additional acpi table format is like I
> > described above. If we want to use the same APIs for config access for
> > coreboot and qemu the API will have to be general enough to accommodate
> > both approaches. Changing formats is not an option at this stage.
> 
> Okay - it doesn't sound like there is much overlap here between qemu
> and coreboot.  On coreboot cbfs is used for pulling out option roms,
> executables, and floppy images - none of which have much use under
> qemu anyway.
> 
> So, maybe we should just go back to the discussion of a config
> interface.  I think it would be nice to have one api for getting
> config items for both qemu and coreboot - something like
> get_config_u32("ShowBootMenu").  On coreboot that info could then be
> extracted from cbfs and qemu can get in from the "cfg port".
> 
> Does that make sense?
> 
Yes. That is the direction I was going to take. Lest implement simple
name/value interface first and table loading code will be different.
If there will be much overlap in table loading code we will unify it
later.

--
			Gleb.
Blue Swirl Sept. 30, 2009, 5:17 p.m. UTC | #11
On Wed, Sep 30, 2009 at 9:35 AM, Gleb Natapov <gleb@redhat.com> wrote:
> On Tue, Sep 29, 2009 at 09:09:46PM -0400, Kevin O'Connor wrote:
>> On Sat, Sep 19, 2009 at 08:56:55PM +0300, Gleb Natapov wrote:
>> > On Sat, Sep 19, 2009 at 11:16:41AM -0400, Kevin O'Connor wrote:
>> > > Maybe a stream could be introduced with something like:
>> > > <name><len><data> <name2><len2><data2> ...
>> > >
>> > The format is already set. The are two ports. You write option id in
>> > first port and you read option value from second one. The value format
>> > is different for each option. Additional acpi table format is like I
>> > described above. If we want to use the same APIs for config access for
>> > coreboot and qemu the API will have to be general enough to accommodate
>> > both approaches. Changing formats is not an option at this stage.
>>
>> Okay - it doesn't sound like there is much overlap here between qemu
>> and coreboot.  On coreboot cbfs is used for pulling out option roms,
>> executables, and floppy images - none of which have much use under
>> qemu anyway.
>>
>> So, maybe we should just go back to the discussion of a config
>> interface.  I think it would be nice to have one api for getting
>> config items for both qemu and coreboot - something like
>> get_config_u32("ShowBootMenu").  On coreboot that info could then be
>> extracted from cbfs and qemu can get in from the "cfg port".
>>
>> Does that make sense?
>>
> Yes. That is the direction I was going to take. Lest implement simple
> name/value interface first and table loading code will be different.
> If there will be much overlap in table loading code we will unify it
> later.

The name/value interface could be useful for OpenBIOS too if we want
to avoid using NVRAM for OpenBIOS variables for compatibility. There
should be methods to iterate through all keys and get the byte size of
the value.

For example, current fw_cfg interface could be extended to allow
string keys in addition to integer keys.
Gleb Natapov Sept. 30, 2009, 5:31 p.m. UTC | #12
On Wed, Sep 30, 2009 at 08:17:26PM +0300, Blue Swirl wrote:
> On Wed, Sep 30, 2009 at 9:35 AM, Gleb Natapov <gleb@redhat.com> wrote:
> > On Tue, Sep 29, 2009 at 09:09:46PM -0400, Kevin O'Connor wrote:
> >> On Sat, Sep 19, 2009 at 08:56:55PM +0300, Gleb Natapov wrote:
> >> > On Sat, Sep 19, 2009 at 11:16:41AM -0400, Kevin O'Connor wrote:
> >> > > Maybe a stream could be introduced with something like:
> >> > > <name><len><data> <name2><len2><data2> ...
> >> > >
> >> > The format is already set. The are two ports. You write option id in
> >> > first port and you read option value from second one. The value format
> >> > is different for each option. Additional acpi table format is like I
> >> > described above. If we want to use the same APIs for config access for
> >> > coreboot and qemu the API will have to be general enough to accommodate
> >> > both approaches. Changing formats is not an option at this stage.
> >>
> >> Okay - it doesn't sound like there is much overlap here between qemu
> >> and coreboot.  On coreboot cbfs is used for pulling out option roms,
> >> executables, and floppy images - none of which have much use under
> >> qemu anyway.
> >>
> >> So, maybe we should just go back to the discussion of a config
> >> interface.  I think it would be nice to have one api for getting
> >> config items for both qemu and coreboot - something like
> >> get_config_u32("ShowBootMenu").  On coreboot that info could then be
> >> extracted from cbfs and qemu can get in from the "cfg port".
> >>
> >> Does that make sense?
> >>
> > Yes. That is the direction I was going to take. Lest implement simple
> > name/value interface first and table loading code will be different.
> > If there will be much overlap in table loading code we will unify it
> > later.
> 
> The name/value interface could be useful for OpenBIOS too if we want
> to avoid using NVRAM for OpenBIOS variables for compatibility. There
> should be methods to iterate through all keys and get the byte size of
> the value.
> 
> For example, current fw_cfg interface could be extended to allow
> string keys in addition to integer keys.
There are two types of string keys. Those that you know the length in
advance (like uuid) and those you don't. fw_cfg can support second type
without additional change by passing <len><string> as a value. This will
be hidden from seabios behind get_config_string() interface of course.

--
			Gleb.
Kevin O'Connor Oct. 2, 2009, 1:08 a.m. UTC | #13
On Wed, Sep 30, 2009 at 08:17:26PM +0300, Blue Swirl wrote:
> The name/value interface could be useful for OpenBIOS too if we want
> to avoid using NVRAM for OpenBIOS variables for compatibility. There
> should be methods to iterate through all keys and get the byte size of
> the value.

Yes - that's what I think would work well for SeaBIOS also.

-Kevin
diff mbox

Patch

diff --git a/Makefile b/Makefile
index ec30f39..a7dd8c8 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@  OUT=out/
 # Source files
 SRCBOTH=output.c util.c block.c floppy.c ata.c misc.c mouse.c kbd.c pci.c \
         serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.c \
-        pnpbios.c pirtable.c vgahooks.c pmm.c ramdisk.c
+        pnpbios.c pirtable.c vgahooks.c pmm.c ramdisk.c pv.c
 SRC16=$(SRCBOTH) system.c disk.c apm.c pcibios.c font.c
 SRC32=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \
       acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \
diff --git a/src/boot.c b/src/boot.c
index b70d49c..083d5b9 100644
--- a/src/boot.c
+++ b/src/boot.c
@@ -12,6 +12,7 @@ 
 #include "bregs.h" // struct bregs
 #include "boot.h" // struct ipl_s
 #include "cmos.h" // inb_cmos
+#include "pv.h"
 
 struct ipl_s IPL;
 
@@ -297,7 +298,8 @@  boot_prep()
         return;
 
     // Allow user to modify BCV/IPL order.
-    interactive_bootmenu();
+    if (qemu_cfg_show_boot_menu())
+        interactive_bootmenu();
 
     // Setup floppy boot order
     int override = IPL.bev[0].subchoice;
diff --git a/src/post.c b/src/post.c
index e2569b0..bd638f8 100644
--- a/src/post.c
+++ b/src/post.c
@@ -19,6 +19,7 @@ 
 #include "bregs.h" // struct bregs
 #include "mptable.h" // mptable_init
 #include "boot.h" // IPL
+#include "pv.h"
 
 void
 __set_irq(int vector, void *loc)
@@ -182,6 +183,8 @@  post()
     serial_setup();
     mouse_setup();
 
+    qemu_cfg_port_probe();
+
     init_bios_tables();
 
     boot_setup();
diff --git a/src/pv.c b/src/pv.c
new file mode 100644
index 0000000..1e2033c
--- /dev/null
+++ b/src/pv.c
@@ -0,0 +1,62 @@ 
+#include "config.h"
+#include "ioport.h"
+#include "pv.h"
+
+int qemu_cfg_present;
+
+static void
+qemu_cfg_select(u16 f)
+{
+    outw(f, QEMU_CFG_CTL_PORT);
+}
+
+static void
+qemu_cfg_read(u8 *buf, int len)
+{
+    while (len--)
+        *(buf++) = inb(PORT_QEMU_CFG_DATA);
+}
+
+static void
+qemu_cfg_read_entry(void *buf, int e, int len)
+{
+    qemu_cfg_select(e);
+    qemu_cfg_read(buf, len);
+}
+
+void qemu_cfg_port_probe(void)
+{
+    char *sig = "QEMU";
+    int i;
+
+    qemu_cfg_present = 1;
+
+    qemu_cfg_select(QEMU_CFG_SIGNATURE);
+
+    for (i = 0; i < 4; i++)
+        if (inb(QEMU_CFG_DATA_PORT) != sig[i]) {
+            qemu_cfg_present = 0;
+            break;
+        }
+    dprintf(4, "qemu_cfg_present=%d\n", qemu_cfg_present);
+}
+
+void qemu_cfg_get_uuid(u8 *uuid)
+{
+    if (!qemu_cfg_present)
+        return;
+
+    qemu_cfg_read_entry(uuid, QEMU_CFG_UUID, 16);
+}
+
+int qemu_cfg_show_boot_menu(void)
+{
+    u16 v;
+    if (!qemu_cfg_present)
+        return 1;
+
+    qemu_cfg_read_entry(&v, QEMU_CFG_BOOT_MENU, sizeof(v));
+
+    return v;
+}
+
diff --git a/src/pv.h b/src/pv.h
new file mode 100644
index 0000000..d4bca80
--- /dev/null
+++ b/src/pv.h
@@ -0,0 +1,46 @@ 
+#ifndef __PV_H
+#define __PV_H
+
+#include "util.h"
+
+/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx.  It
+ * should be used to determine that a VM is running under KVM.
+ */
+#define KVM_CPUID_SIGNATURE     0x40000000
+
+static inline int kvm_para_available(void)
+{
+    unsigned int eax, ebx, ecx, edx;
+    char signature[13];
+
+    cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
+    memcpy(signature + 0, &ebx, 4);
+    memcpy(signature + 4, &ecx, 4);
+    memcpy(signature + 8, &edx, 4);
+    signature[12] = 0;
+
+    if (strcmp(signature, "KVMKVMKVM") == 0)
+        return 1;
+
+    return 0;
+}
+
+#define QEMU_CFG_CTL_PORT		0x510
+#define QEMU_CFG_DATA_PORT		0x511
+#define QEMU_CFG_SIGNATURE		0x00
+#define QEMU_CFG_ID			0x01
+#define QEMU_CFG_UUID			0x02
+#define QEMU_CFG_NUMA			0x0d
+#define QEMU_CFG_BOOT_MENU		0x0e
+#define QEMU_CFG_MAX_CPUS		0x0f
+#define QEMU_CFG_ARCH_LOCAL		0x8000
+#define QEMU_CFG_ACPI_TABLES		(QEMU_CFG_ARCH_LOCAL + 0)
+#define QEMU_CFG_SMBIOS_ENTRIES		(QEMU_CFG_ARCH_LOCAL + 1)
+
+extern int qemu_cfg_present;
+
+void qemu_cfg_port_probe(void);
+int qemu_cfg_show_boot_menu(void);
+void qemu_cfg_get_uuid(u8 *uuid);
+
+#endif
diff --git a/src/smbios.c b/src/smbios.c
index 6fbddd9..3223b80 100644
--- a/src/smbios.c
+++ b/src/smbios.c
@@ -7,7 +7,7 @@ 
 
 #include "util.h" // dprintf
 #include "biosvar.h" // GET_EBDA
-
+#include "pv.h"
 
 /****************************************************************
  * UUID probe
@@ -18,23 +18,6 @@ 
 #define QEMU_CFG_UUID       0x02
 
 static void
-qemu_cfg_read(u8 *buf, u16 f, int len)
-{
-    outw(f, PORT_QEMU_CFG_CTL);
-    while (len--)
-        *(buf++) = inb(PORT_QEMU_CFG_DATA);
-}
-
-static int
-qemu_cfg_port_probe()
-{
-    u8 sig[4] = "QEMU";
-    u8 buf[4];
-    qemu_cfg_read(buf, QEMU_CFG_SIGNATURE, 4);
-    return *(u32*)buf == *(u32*)sig;
-}
-
-static void
 uuid_probe(u8 *bios_uuid)
 {
     // Default to UUID not set
@@ -44,11 +27,8 @@  uuid_probe(u8 *bios_uuid)
         return;
     if (CONFIG_COREBOOT)
         return;
-    if (! qemu_cfg_port_probe())
-        // Feature not available
-        return;
 
-    qemu_cfg_read(bios_uuid, QEMU_CFG_UUID, 16);
+    qemu_cfg_get_uuid(bios_uuid);
 }