Re: [RFC/PATCH 1/2] kvm tools, seabios: Add "--bios" option to "vm run"

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 02/24/2012 09:05 AM, Pekka Enberg wrote:
This patch adds a "--bios" command line option to "vm run". You can use this to
try to boot with SeaBIOS, for example:

   ./vm run --bios=/usr/share/seabios/bios.bin \
	 --disk $HOME/images/debian_lenny_amd64_standard.qcow2

This doesn't boot yet for obvious reasons but at least people can now start to
play with external BIOS images easily.

You may want to call it firmware as other platforms also have firmware. For instance, it may be desirable to use the same interface to load SLOF with spapr.


Cc: Yang Bai<hamo.by@xxxxxxxxx>
Cc: Matt Evans<matt@xxxxxxxxxx>
Cc: Ron Minnich<rminnich@xxxxxxxxx>
Cc: Anthony Liguori<aliguori@xxxxxxxxxx>
Cc: John Floren<john@xxxxxxxxxxx>
Cc: Sasha Levin<levinsasha928@xxxxxxxxx>
Cc: Cyrill Gorcunov<gorcunov@xxxxxxxxxx>
Cc: Asias He<asias.hejun@xxxxxxxxx>
Cc: Ingo Molnar<mingo@xxxxxxx>
Signed-off-by: Pekka Enberg<penberg@xxxxxxxxxx>
---
  tools/kvm/Makefile               |    2 +
  tools/kvm/builtin-run.c          |   32 +++++++++++++++++++----------
  tools/kvm/include/kvm/kvm.h      |    1 +
  tools/kvm/powerpc/boot.c         |    8 +++++++
  tools/kvm/x86/boot.c             |   41 ++++++++++++++++++++++++++++++++++++++
  tools/kvm/x86/include/kvm/bios.h |    3 +-
  6 files changed, 75 insertions(+), 12 deletions(-)
  create mode 100644 tools/kvm/powerpc/boot.c
  create mode 100644 tools/kvm/x86/boot.c

diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile
index cfa5547..0a9c2cc 100644
--- a/tools/kvm/Makefile
+++ b/tools/kvm/Makefile
@@ -113,6 +113,7 @@ LIBFDT_OBJS = $(patsubst %,../../scripts/dtc/libfdt/%,$(LIBFDT_SRC))
  #x86
  ifeq ($(ARCH),x86)
  	DEFINES += -DCONFIG_X86
+	OBJS	+= x86/boot.o
  	OBJS	+= x86/cpuid.o
  	OBJS	+= x86/interrupt.o
  	OBJS	+= x86/ioport.o
@@ -129,6 +130,7 @@ endif
  # POWER/ppc:  Actually only support ppc64 currently.
  ifeq ($(uname_M), ppc64)
  	DEFINES += -DCONFIG_PPC
+	OBJS	+= powerpc/boot.o
  	OBJS	+= powerpc/ioport.o
  	OBJS	+= powerpc/irq.o
  	OBJS	+= powerpc/kvm.o
diff --git a/tools/kvm/builtin-run.c b/tools/kvm/builtin-run.c
index 466169e..f96c581 100644
--- a/tools/kvm/builtin-run.c
+++ b/tools/kvm/builtin-run.c
@@ -76,6 +76,7 @@ static const char *kernel_cmdline;
  static const char *kernel_filename;
  static const char *vmlinux_filename;
  static const char *initrd_filename;
+static const char *bios_filename;
  static const char *image_filename[MAX_DISK_IMAGES];
  static const char *console;
  static const char *dev;
@@ -458,6 +459,8 @@ static const struct option options[] = {
  			"Initial RAM disk image"),
  	OPT_STRING('p', "params",&kernel_cmdline, "params",
  			"Kernel command line arguments"),
+	OPT_STRING('b', "bios",&bios_filename, "bios",
+			"BIOS to boot in virtual machine"),

  	OPT_GROUP("Networking options:"),
  	OPT_CALLBACK_DEFAULT('n', "network", NULL, "network params",
@@ -1110,14 +1113,16 @@ static int kvm_cmd_run_init(int argc, const char **argv)
  	printf("  # %s run -k %s -m %Lu -c %d --name %s\n", KVM_BINARY_NAME,
  		kernel_filename, ram_size / 1024 / 1024, nrcpus, guest_name);

-	if (!kvm__load_kernel(kvm, kernel_filename, initrd_filename,
-				real_cmdline, vidmode))
-		die("unable to load kernel %s", kernel_filename);
+	if (!bios_filename) {
+		if (!kvm__load_kernel(kvm, kernel_filename,
+				initrd_filename, real_cmdline, vidmode))
+			die("unable to load kernel %s", kernel_filename);

-	kvm->vmlinux = vmlinux_filename;
-	r = symbol_init(kvm);
-	if (r<  0)
-		pr_debug("symbol_init() failed with error %d\n", r);
+		kvm->vmlinux = vmlinux_filename;
+		r = symbol_init(kvm);
+		if (r<  0)
+			pr_debug("symbol_init() failed with error %d\n", r);
+	}

  	ioport__setup_arch();

@@ -1218,10 +1223,15 @@ static int kvm_cmd_run_init(int argc, const char **argv)

  	kvm__start_timer(kvm);

-	kvm__arch_setup_firmware(kvm);
-	if (r<  0) {
-		pr_err("kvm__arch_setup_firmware() failed with error %d\n", r);
-		goto fail;
+	if (bios_filename) {
+		if (!kvm__load_bios(kvm, bios_filename))
+			die("unable to load bios %s: %s", bios_filename, strerror(errno));
+	} else {
+		kvm__arch_setup_firmware(kvm);
+		if (r<  0) {
+			pr_err("kvm__arch_setup_firmware() failed with error %d\n", r);
+			goto fail;
+		}
  	}

  	for (i = 0; i<  nrcpus; i++) {
diff --git a/tools/kvm/include/kvm/kvm.h b/tools/kvm/include/kvm/kvm.h
index 7870118..258d11a 100644
--- a/tools/kvm/include/kvm/kvm.h
+++ b/tools/kvm/include/kvm/kvm.h
@@ -39,6 +39,7 @@ int kvm__recommended_cpus(struct kvm *kvm);
  int kvm__max_cpus(struct kvm *kvm);
  void kvm__init_ram(struct kvm *kvm);
  int kvm__exit(struct kvm *kvm);
+bool kvm__load_bios(struct kvm *kvm, const char *bios_filename);
  bool kvm__load_kernel(struct kvm *kvm, const char *kernel_filename,
  			const char *initrd_filename, const char *kernel_cmdline, u16 vidmode);
  void kvm__start_timer(struct kvm *kvm);
diff --git a/tools/kvm/powerpc/boot.c b/tools/kvm/powerpc/boot.c
new file mode 100644
index 0000000..8c99831
--- /dev/null
+++ b/tools/kvm/powerpc/boot.c
@@ -0,0 +1,8 @@
+#include "kvm/kvm.h"
+
+#include<stdbool.h>
+
+bool kvm__load_bios(struct kvm *kvm, const char *bios_filename)
+{
+	return false;
+}
diff --git a/tools/kvm/x86/boot.c b/tools/kvm/x86/boot.c
new file mode 100644
index 0000000..383d9f7
--- /dev/null
+++ b/tools/kvm/x86/boot.c
@@ -0,0 +1,41 @@
+#include "kvm/kvm.h"
+
+#include "kvm/util.h"
+
+#include<sys/types.h>
+#include<sys/stat.h>
+#include<stdbool.h>
+#include<fcntl.h>
+
+#define BIOS_SELECTOR	0xf000
+#define BIOS_IP		0xfff0
+#define BIOS_SP		0x8000
+
+bool kvm__load_bios(struct kvm *kvm, const char *bios_filename)
+{
+	struct stat st;
+	void *p;
+	int fd;
+	int nr;
+
+	fd = open(bios_filename, O_RDONLY);
+	if (fd<  0)
+		return false;
+
+	if (fstat(fd,&st))
+		return false;
+
+	if (st.st_size>  MB_BIOS_SIZE)
+		die("BIOS image %s is too big to fit in memory (%lu KB).\n", bios_filename, st.st_size / 1024);
+
+	p = guest_flat_to_host(kvm, MB_BIOS_BEGIN);
+
+	while ((nr = read(fd, p, st.st_size))>  0)
+		p += nr;
+
+	kvm->boot_selector	= BIOS_SELECTOR;
+	kvm->boot_ip		= BIOS_IP;
+	kvm->boot_sp		= BIOS_SP;
+
+	return true;
+}
diff --git a/tools/kvm/x86/include/kvm/bios.h b/tools/kvm/x86/include/kvm/bios.h
index de569bc..9d677ae 100644
--- a/tools/kvm/x86/include/kvm/bios.h
+++ b/tools/kvm/x86/include/kvm/bios.h
@@ -26,8 +26,9 @@

  #define E820_MAP_START			EBDA_START

-#define MB_BIOS_BEGIN			0x000f0000
+#define MB_BIOS_BEGIN			0x000e0000
  #define MB_BIOS_END			0x000fffff
+#define MB_BIOS_SIZE			(MB_BIOS_END - MB_BIOS_BEGIN + 1)

  #define VGA_RAM_BEGIN			0x000a0000
  #define VGA_RAM_END			0x000bffff

FYI, this will work with SeaBIOS because it's currently 128k. But the normal thing is to load the last 128k of the BIOS ROM at 1MB - 128k, with the full ROM mapped at 4GB - sizeof(ROM).

SeaBIOS certainly expects the ROM to be located in both places.

Also note that the area at 1MB - 128k is special. There's two distinct regions mapped here, normal RAM and then the BIOS ROM. Depending on the settings of the PAM registers, a guest can chose to see either piece of memory. In fact, it can control read and write access independently such that writes go to RAM and reads come from the BIOS area.

This is used to implement shadowing. SeaBIOS does special case this under KVM since it's not possible to execute out of MMIO under KVM.

Regards,

Anthony Liguori

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux