diff --git a/Makefile b/Makefile
index eb8ad583ae..6ea8e19ee7 100644
--- a/Makefile
+++ b/Makefile
@@ -92,6 +92,7 @@ endif
 
 target-y :=
 target-$(CONFIG_QEMU) += $(OUT)bios.bin
+target-$(CONFIG_KVMTOOL) += $(OUT)bios.bin
 target-$(CONFIG_CSM) += $(OUT)Csm16.bin
 target-$(CONFIG_COREBOOT) += $(OUT)bios.bin.elf
 target-$(CONFIG_BUILD_VGABIOS) += $(OUT)vgabios.bin
diff --git a/src/fw/paravirt.h b/src/fw/paravirt.h
index a14d83e101..57ee0cfc4d 100644
--- a/src/fw/paravirt.h
+++ b/src/fw/paravirt.h
@@ -60,4 +60,7 @@ int qemu_cfg_write_file(void *src, struct romfile_s *file, u32 offset, u32 len);
 int qemu_cfg_write_file_simple(void *src, u16 key, u32 offset, u32 len);
 u16 qemu_get_romfile_key(struct romfile_s *file);
 
+void kvmtool_preinit(void);
+void kvmtool_platform_setup(void);
+
 #endif
diff --git a/src/fw/paravirt.c b/src/fw/paravirt.c
index 9674ab8ba8..0d4855e2e2 100644
--- a/src/fw/paravirt.c
+++ b/src/fw/paravirt.c
@@ -621,3 +621,51 @@ void qemu_cfg_init(void)
         dprintf(1, "Moving pm_base to 0x%x\n", acpi_pm_base);
     }
 }
+
+void
+kvmtool_platform_setup(void)
+{
+    if (!CONFIG_KVMTOOL)
+        return;
+
+    pci_probe_devices();
+}
+
+void
+kvmtool_preinit(void)
+{
+    /*
+     * When started without firmware kvmtool creates a e820 map for
+     * the guest kernel.  When started with "--firmware $file" it
+     * doesn't, so we have to figure.
+     *
+     * Detects only memory below 4G for now as we run in 32bit mode.
+     * For memory above 4G we would have to:
+     *    (1) get hints from kvmtool somehow, or
+     *    (2) enable paging, or
+     *    (3) enter long mode.
+     *
+     * There is a 768M memory hole for I/O,
+     * see x86/include/kvm/kvm-arch.h in kvmtool.
+     */
+    static const u32 max_mb_32bit = 4096 - 768;
+    u32 mb, *ptr;
+
+    if (!CONFIG_KVMTOOL)
+        return;
+
+    for (mb = 16; mb < max_mb_32bit; mb++) {
+        ptr = (void*)(mb * 1024 * 1024 - 4);
+        *ptr = mb;
+    }
+    for (mb = 16; mb < max_mb_32bit; mb++) {
+        ptr = (void*)(mb * 1024 * 1024 - 4);
+        if (*ptr != mb)
+            break;
+        RamSize = mb * 1024 * 1024;
+    }
+
+    dprintf(1,"kvmtool: probed %d MB low RAM.\n",
+            RamSize / (1024 * 1024));
+    e820_add(0, RamSize, E820_RAM);
+}
diff --git a/src/post.c b/src/post.c
index f93106a1c9..f7268ecb8f 100644
--- a/src/post.c
+++ b/src/post.c
@@ -147,6 +147,7 @@ platform_hardware_setup(void)
 
     // Platform specific setup
     qemu_platform_setup();
+    kvmtool_platform_setup();
     coreboot_platform_setup();
 
     // Setup timers and periodic clock interrupt
@@ -307,6 +308,7 @@ dopost(void)
 
     // Detect ram and setup internal malloc.
     qemu_preinit();
+    kvmtool_preinit();
     coreboot_preinit();
     malloc_preinit();
 
@@ -320,7 +322,7 @@ dopost(void)
 void VISIBLE32FLAT
 handle_post(void)
 {
-    if (!CONFIG_QEMU && !CONFIG_COREBOOT)
+    if (!CONFIG_QEMU && !CONFIG_COREBOOT && !CONFIG_KVMTOOL)
         return;
 
     serial_debug_preinit();
diff --git a/src/sercon.c b/src/sercon.c
index 5d27051efb..0b7722ec08 100644
--- a/src/sercon.c
+++ b/src/sercon.c
@@ -517,6 +517,8 @@ void sercon_setup(void)
     u16 addr;
 
     addr = romfile_loadint("etc/sercon-port", 0);
+    if (!addr && CONFIG_KVMTOOL)
+        addr = 0x3f8;
     if (!addr)
         return;
     dprintf(1, "sercon: using ioport 0x%x\n", addr);
diff --git a/src/Kconfig b/src/Kconfig
index 00108057d7..985594c51b 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -25,6 +25,11 @@ choice
            Configure to be used by EFI firmware as Compatibility Support
            module (CSM) to provide legacy BIOS services.
 
+    config KVMTOOL
+        bool "Build for kvmtool"
+        help
+            Configure for an emulated machine (kvmtool).
+
 endchoice
 
     config QEMU_HARDWARE
@@ -61,6 +66,7 @@ endchoice
             Support an interactive boot menu at end of post.
     config BOOTSPLASH
         depends on BOOTMENU
+        depends on !KVMTOOL
         bool "Graphical boot splash screen"
         default y
         help
@@ -124,6 +130,7 @@ endchoice
 
     config ROM_SIZE
         int "ROM size (in KB)"
+        default 128 if KVMTOOL
         default 0
         help
             Set the ROM size.  Say '0' here to make seabios figure the
@@ -138,6 +145,7 @@ endmenu
 menu "Hardware support"
     config ATA
         depends on DRIVES
+        depends on !KVMTOOL
         bool "ATA controllers"
         default y
         help
@@ -156,24 +164,26 @@ menu "Hardware support"
             Use 32bit PIO accesses on ATA (minor optimization on PCI transfers).
     config AHCI
         depends on DRIVES
+        depends on !KVMTOOL
         bool "AHCI controllers"
         default y
         help
             Support for AHCI disk code.
     config SDCARD
         depends on DRIVES
+        depends on !KVMTOOL
         bool "SD controllers"
         default y
         help
             Support for SD cards on PCI host controllers.
     config VIRTIO_BLK
-        depends on DRIVES && QEMU_HARDWARE
+        depends on DRIVES && (QEMU_HARDWARE || KVMTOOL)
         bool "virtio-blk controllers"
         default y
         help
             Support boot from virtio-blk storage.
     config VIRTIO_SCSI
-        depends on DRIVES && QEMU_HARDWARE
+        depends on DRIVES && (QEMU_HARDWARE || KVMTOOL)
         bool "virtio-scsi controllers"
         default y
         help
@@ -204,6 +214,7 @@ menu "Hardware support"
             Support boot from qemu-emulated lsi53c895a scsi storage.
     config MEGASAS
         depends on DRIVES
+        depends on !KVMTOOL
         bool "LSI MegaRAID SAS controllers"
         default y
         help
@@ -216,6 +227,7 @@ menu "Hardware support"
             Support boot from LSI MPT Fusion scsi storage.
     config FLOPPY
         depends on DRIVES && HARDWARE_IRQ
+        depends on !KVMTOOL
         bool "Floppy controller"
         default y
         help
@@ -229,6 +241,7 @@ menu "Hardware support"
             QEMU fw_cfg.
     config NVME
         depends on DRIVES
+        depends on !KVMTOOL
         bool "NVMe controllers"
         default y
         help
@@ -236,6 +249,7 @@ menu "Hardware support"
 
     config PS2PORT
         depends on KEYBOARD || MOUSE
+        depends on !KVMTOOL
         bool "PS/2 port"
         default y
         help
@@ -243,6 +257,7 @@ menu "Hardware support"
 
     config USB
         bool "USB"
+        depends on !KVMTOOL
         default y
         help
             Support USB devices.
@@ -355,6 +370,7 @@ menu "Hardware support"
             Initialize the Memory Type Range Registers (on emulators).
     config PMTIMER
         bool "Support ACPI timer"
+        depends on !KVMTOOL
         default y
         help
             Detect and use the ACPI timer for timekeeping.
@@ -404,6 +420,7 @@ menu "BIOS interfaces"
     config OPTIONROMS
         bool "Option ROMS"
         default y
+        depends on !KVMTOOL
         help
             Support finding and running option roms during POST.
     config PMM
@@ -466,6 +483,7 @@ menu "BIOS interfaces"
 
     config TCGBIOS
         depends on S3_RESUME
+        depends on !KVMTOOL
         bool "TPM support and TCG BIOS extensions"
         default y
         help
@@ -493,6 +511,7 @@ menu "BIOS Tables"
             sometimes called DMI.
     config ACPI
         bool "ACPI"
+        depends on !KVMTOOL
         default y
         help
             Support generation of ACPI tables.
