Hmm, the last patch includes a binary. So please take this patch instead.

Thanks,
Q

# diffstat linuxboot1.diff
 Makefile             |   13 ++++-
 linuxboot/Makefile   |   40 +++++++++++++++
 linuxboot/boot.S     |   54 +++++++++++++++++++++
 linuxboot/farvar.h   |  130 +++++++++++++++++++++++++++++++++++++++++++++++++++
 linuxboot/rom.c      |  104 ++++++++++++++++++++++++++++++++++++++++
 linuxboot/signrom.c  |  128 ++++++++++++++++++++++++++++++++++++++++++++++++++
 linuxboot/util.h     |   69 +++++++++++++++++++++++++++
 qemu/Makefile        |    3 -
 qemu/Makefile.target |    2
 qemu/hw/linuxboot.c  |   39 +++++++++++++++
 qemu/hw/pc.c         |   22 +++++++-
 qemu/hw/pc.h         |    5 +
 12 files changed, 600 insertions(+), 9 deletions(-)





On Mon, Apr 21, 2008 at 12:33 PM, Nguyen Anh Quynh <[EMAIL PROTECTED]> wrote:
> Forget to say that this patch is against kvm-66.
>
>  Thanks,
>  Q
>
>
>
>  On Mon, Apr 21, 2008 at 12:32 PM, Nguyen Anh Quynh <[EMAIL PROTECTED]> wrote:
>  > Hi,
>  >
>  >  This should be submitted to upstream (but not to kvm-devel list), but
>  >  this is only the test code that I want to quickly send out for
>  >  comments. In case it looks OK, I will send it to upstream later.
>  >
>  >  Inspired by extboot and conversations with Anthony and HPA, this
>  >  linuxboot option ROM is a simple option ROM that intercepts int19 in
>  >  order to execute linux setup code. This approach eliminates the need
>  >  to manipulate the boot sector for this purpose.
>  >
>  >  To test it, just load linux kernel with your KVM/QEMU image using
>  >  -kernel option in normal way.
>  >
>  >  I succesfully compiled and tested it with kvm-66 on Ubuntu 7.10, guest
>  >  Ubuntu 8.04.
>  >
>  >  Thanks,
>  >  Quynh
>  >
>  >
>  >  # diffstat linuxboot1.diff
>  >   Makefile             |   13 ++++-
>  >   linuxboot/Makefile   |   40 +++++++++++++++
>  >   linuxboot/boot.S     |   54 +++++++++++++++++++++
>  >   linuxboot/farvar.h   |  130 
> +++++++++++++++++++++++++++++++++++++++++++++++++++
>  >   linuxboot/rom.c      |  104 ++++++++++++++++++++++++++++++++++++++++
>  >   linuxboot/signrom    |binary
>  >   linuxboot/signrom.c  |  128 
> ++++++++++++++++++++++++++++++++++++++++++++++++++
>  >   linuxboot/util.h     |   69 +++++++++++++++++++++++++++
>  >   qemu/Makefile        |    3 -
>  >   qemu/Makefile.target |    2
>  >   qemu/hw/linuxboot.c  |   39 +++++++++++++++
>  >   qemu/hw/pc.c         |   22 +++++++-
>  >   qemu/hw/pc.h         |    5 +
>  >   13 files changed, 600 insertions(+), 9 deletions(-)
>  >
>
commit f4f1178898c8a4bbbc0a432354dbcc56353099c3
Author: Nguyen Anh Quynh <[EMAIL PROTECTED]>
Date:   Mon Apr 21 12:27:47 2008 +0900

    Linuxboot Option ROM support.
    
    Signed-off-by: Nguyen Anh Quynh <[EMAIL PROTECTED]>

diff --git a/Makefile b/Makefile
index 76c149a..fdd9388 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ DESTDIR=
 
 rpmrelease = devel
 
-.PHONY: kernel user libkvm qemu bios vgabios extboot clean libfdt
+.PHONY: kernel user libkvm qemu bios vgabios extboot linuxboot clean libfdt
 
 all: libkvm qemu
 ifneq '$(filter $(ARCH), x86_64 i386 ia64)' ''
@@ -19,7 +19,7 @@ qemu kernel user libkvm:
 
 qemu: libkvm
 ifneq '$(filter $(ARCH), i386 x86_64)' ''
-    qemu: extboot
+    qemu: extboot linuxboot
 endif
 ifneq '$(filter $(ARCH), powerpc)' ''
     qemu: libfdt
@@ -41,6 +41,14 @@ extboot:
            || ! cmp -s qemu/pc-bios/extboot.bin extboot/extboot.bin; then \
 		cp extboot/extboot.bin qemu/pc-bios/extboot.bin; \
 	fi
+
+linuxboot:
+	$(MAKE) -C $@
+	if ! [ -f qemu/pc-bios/linuxboot.bin ] \
+           || ! cmp -s qemu/pc-bios/linuxboot.bin linuxboot/linuxboot.bin; then \
+		cp linuxboot/linuxboot.bin qemu/pc-bios/linuxboot.bin; \
+	fi
+
 libfdt:
 	$(MAKE) -C $@
 
@@ -88,6 +96,7 @@ srpm:
 	tar czf $(RPMTOPDIR)/SOURCES/kernel.tar.gz kernel
 	tar czf $(RPMTOPDIR)/SOURCES/scripts.tar.gz scripts
 	tar czf $(RPMTOPDIR)/SOURCES/extboot.tar.gz extboot
+	tar czf $(RPMTOPDIR)/SOURCES/linuxboot.tar.gz linuxboot
 	cp Makefile configure kvm_stat $(RPMTOPDIR)/SOURCES
 	rpmbuild  --define="_topdir $(RPMTOPDIR)" -bs $(tmpspec)
 	$(RM) $(tmpspec)
diff --git a/linuxboot/Makefile b/linuxboot/Makefile
new file mode 100644
index 0000000..3bc88a6
--- /dev/null
+++ b/linuxboot/Makefile
@@ -0,0 +1,40 @@
+# Makefile for linuxboot Option ROM
+# Nguyen Anh Quynh <[EMAIL PROTECTED]>
+
+CC = gcc
+CCFLAGS = -g -Wall -Werror -nostdlib -fno-builtin -fomit-frame-pointer -Os
+
+cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \
+              /dev/null 2>&1`"; then echo "$(2)"; else echo "$(3)"; fi ;)
+CCFLAGS += $(call cc-option,$(CC),-nopie,)
+CCFLAGS += $(call cc-option,$(CC),-fno-stack-protector,)
+CCFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,)
+
+INSTALLDIR = /usr/share/qemu
+
+.PHONY: all
+all: clean linuxboot.bin
+
+.PHONY: install
+install: linuxboot.bin
+	cp linuxboot.bin $(INSTALLDIR)
+
+.PHONY: clean
+clean:
+	$(RM) *.o *.img *.bin signrom *~
+
+linuxboot.img: boot.o rom.o
+	$(LD) --oformat binary -Ttext 0 $^ -o $@ 
+
+linuxboot.bin: linuxboot.img signrom
+	./signrom linuxboot.img linuxboot.bin
+
+signrom: signrom.c
+	$(CC) -o $@ -g -Wall $^
+
+%.o: %.c
+	$(CC) $(CCFLAGS) -c $<
+
+%.o: %.S
+	$(CC) $(CCFLAGS) -c $<
+
diff --git a/linuxboot/boot.S b/linuxboot/boot.S
new file mode 100644
index 0000000..a9461d6
--- /dev/null
+++ b/linuxboot/boot.S
@@ -0,0 +1,54 @@
+/*
+ * boot.S
+ * Linux Boot Option ROM for QEMU.
+
+ * Copyright (C) by Nguyen Anh Quynh <[EMAIL PROTECTED]>, 2008. 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+	.text
+	.code16gcc
+	.globl _start
+	.extern setup
+_start:
+	.short 0xAA55		/* ROM signature */
+	.byte 0				/* ROM size - to be patched at built-time */
+	/* ROM entry: initializing */
+	pushal
+	/* %es is clobbered, so save it */
+	pushw %es
+    /* just in case */
+	pushw %ds
+	cld
+	call setup		/* call C code */
+	popw  %ds
+	popw  %es
+	popal
+	lretw
+
+	/* interrupt 19 handler */
+	.globl int19_handler
+	.extern int19_handler_C
+	.extern linux_boot
+	int19_handler:
+	/* we never execute the original int19, so no need to care
+	 * about clobbered registers :-) */
+	/* Set %ds = %ss */
+	movw %ss, %ax
+	movw %ax, %ds
+	cld
+	call int19_handler_C	/* call C code */
+	/* we actually jump to linux kernel setup, so never reach here */
diff --git a/linuxboot/farvar.h b/linuxboot/farvar.h
new file mode 100644
index 0000000..7876186
--- /dev/null
+++ b/linuxboot/farvar.h
@@ -0,0 +1,130 @@
+/*
+ * farvar.h
+ * Code to access multiple segments within gcc.
+ *
+ * Copyright (C) 2008  Kevin O'Connor <[EMAIL PROTECTED]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __FARVAR_H
+#define __FARVAR_H
+
+#include <stdint.h>
+
+// Dummy definitions used to make sure gcc understands dependencies
+// between SET_SEG and GET/READ/WRITE_SEG macros.
+extern uint16_t __segment_CS, __segment_DS, __segment_ES, __segment_SS;
+extern uint16_t __segment_GS, __segment_FS;
+
+// Low level macros for reading/writing memory via a segment selector.
+#define __READ8_SEG(SEG, var) ({                            \
+		typeof(var) __value;                                \
+		__asm__("movb %%" #SEG ":%1, %b0" : "=Qi"(__value)  \
+			: "m"(var), "m"(__segment_ ## SEG));            \
+		__value; })
+#define __READ16_SEG(SEG, var) ({                           \
+		typeof(var) __value;                                \
+		__asm__("movw %%" #SEG ":%1, %w0" : "=ri"(__value)  \
+			: "m"(var), "m"(__segment_ ## SEG));            \
+		__value; })
+#define __READ32_SEG(SEG, var) ({                           \
+		typeof(var) __value;                                \
+		__asm__("movl %%" #SEG ":%1, %0" : "=ri"(__value)   \
+			: "m"(var), "m"(__segment_ ## SEG));            \
+		__value; })
+
+#define __WRITE8_SEG(SEG, var, value)                       \
+	__asm__("movb %b1, %%" #SEG ":%0" : "=m"(var)           \
+			: "Q"(value), "m"(__segment_ ## SEG))
+#define __WRITE16_SEG(SEG, var, value)                      \
+	__asm__("movw %w1, %%" #SEG ":%0" : "=m"(var)           \
+			: "r"(value), "m"(__segment_ ## SEG))
+#define __WRITE32_SEG(SEG, var, value)                      \
+	__asm__("movl %1, %%" #SEG ":%0" : "=m"(var)            \
+			: "r"(value), "m"(__segment_ ## SEG))
+
+// Low level macros for getting/setting a segment register.
+#define __SET_SEG(SEG, value)                                   \
+	__asm__("movw %w1, %%" #SEG : "=m"(__segment_ ## SEG)       \
+			: "r"(value))
+#define __GET_SEG(SEG) ({                                       \
+		uint16_t __seg;                                         \
+		__asm__("movw %%" #SEG ", %w0" : "=r"(__seg)            \
+			: "m"(__segment_ ## SEG));                          \
+		__seg;})
+
+// Macros for automatically choosing the appropriate memory size
+// access method.
+extern void __force_link_error__unknown_type();
+
+#define __GET_VAR(seg, var) ({                                          \
+		typeof(var) __val;                                              \
+		if (__builtin_types_compatible_p(typeof(__val), uint8_t)        \
+			|| __builtin_types_compatible_p(typeof(__val), int8_t))     \
+		__val = __READ8_SEG(seg, var);                                  \
+		else if (__builtin_types_compatible_p(typeof(__val), uint16_t)  \
+			|| __builtin_types_compatible_p(typeof(__val), int16_t))    \
+		__val = __READ16_SEG(seg, var);                                 \
+		else if (__builtin_types_compatible_p(typeof(__val), uint32_t)  \
+			|| __builtin_types_compatible_p(typeof(__val), int32_t))    \
+		__val = __READ32_SEG(seg, var);                                 \
+		else                                                            \
+		__force_link_error__unknown_type();                             \
+		__val; })
+
+#define __SET_VAR(seg, var, val) do {                                   \
+	if (__builtin_types_compatible_p(typeof(var), uint8_t)              \
+			|| __builtin_types_compatible_p(typeof(var), int8_t))       \
+	__WRITE8_SEG(seg, var, (val));                                      \
+	else if (__builtin_types_compatible_p(typeof(var), uint16_t)        \
+			|| __builtin_types_compatible_p(typeof(var), int16_t))      \
+	__WRITE16_SEG(seg, var, (val));                                     \
+	else if (__builtin_types_compatible_p(typeof(var), uint32_t)        \
+			|| __builtin_types_compatible_p(typeof(var), int32_t))      \
+	__WRITE32_SEG(seg, var, (val));                                     \
+	else                                                                \
+	__force_link_error__unknown_type();                                 \
+} while (0)
+
+// Macros for converting to/from 32bit style pointers to their
+// equivalent 16bit segment/offset values.
+#define FARPTR_TO_SEG(p) (((u32)(p)) >> 4)
+#define FARPTR_TO_OFFSET(p) (((u32)(p)) & 0xf)
+#define MAKE_FARPTR(seg,off) ((void*)(((seg)<<4)+(off)))
+
+// Macros for accessing a variable in another segment.  (They
+// automatically update the %es segment and then make the appropriate
+// access.)
+#define __GET_FARVAR(seg, var) ({               \
+		SET_SEG(ES, (seg));                     \
+		GET_VAR(ES, (var)); })
+
+#define __SET_FARVAR(seg, var, val) do {        \
+	typeof(var) __sfv_val = (val);              \
+	SET_SEG(ES, (seg));                         \
+	SET_VAR(ES, (var), __sfv_val);              \
+} while (0)
+
+#define GET_FARVAR(seg, var) __GET_FARVAR((seg), (var))
+#define SET_FARVAR(seg, var, val) __SET_FARVAR((seg), (var), (val))
+
+#define GET_VAR(seg, var) __GET_VAR(seg, (var))
+#define SET_VAR(seg, var, val) __SET_VAR(seg, (var), (val))
+
+#define SET_SEG(SEG, value) __SET_SEG(SEG, (value))
+#define GET_SEG(SEG) __GET_SEG(SEG)
+
+#endif
diff --git a/linuxboot/rom.c b/linuxboot/rom.c
new file mode 100644
index 0000000..4cd600d
--- /dev/null
+++ b/linuxboot/rom.c
@@ -0,0 +1,104 @@
+/*
+ * rom.c
+ * Linux Boot Option ROM for QEMU.
+ *
+ * Copyright (C) by Nguyen Anh Quynh <[EMAIL PROTECTED]>, 2008. 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "util.h"
+#include "farvar.h"
+
+asm (".code16gcc");
+
+struct linuxboot_info {
+	uint16_t cs;		/* CS segment */
+	uint16_t ds;		/* DS segment */
+	uint16_t sp;		/* SP reg */
+};
+
+#define LINUXBOOT_PORT 0x407
+
+struct ivector {
+	uint16_t offset;
+	uint16_t segment;
+};
+/* manipulate interrupt vector entry */
+#define GET_IVT_ENTRY(index,var) \
+    GET_FARVAR(0, ((struct ivector *)(index*sizeof(struct ivector)))->var)
+#define SET_IVT_ENTRY(index,var,value) \
+    SET_FARVAR(0, ((struct ivector *)(index*sizeof(struct ivector)))->var, value)
+
+/* called from ASM code in boot.S */
+void setup()
+{
+	/* install our INT 19 handler */
+	extern void int19_handler;
+	SET_IVT_ENTRY(0x19, segment, GET_SEG(CS));
+	SET_IVT_ENTRY(0x19, offset, (uint16_t)&int19_handler);
+}
+
+/* send command to QEMU via a dedicated IO port */
+static void get_linuxboot_info(struct linuxboot_info *info)
+{
+	uint16_t seg;
+	char tmp[16 + sizeof(*info)], *p;
+
+	/* align to 16 */
+	p = (char *)(((uint32_t)tmp + 0xF) & ~0xF);
+	memcpy(p, info, sizeof(*info));
+
+	/* send segment contained info to QEMU */
+	seg = ((uint32_t)p >> 4) + GET_SEG(SS);
+	outw(seg, LINUXBOOT_PORT);
+
+	/* now copy back the result to info */
+	memcpy(info, p, sizeof(*info));
+}
+
+/* boot linux by jmp to its kernel setup code */
+static void boot_linux(uint16_t cs, uint16_t ds, uint16_t sp)
+{
+	asm volatile (
+			"cli             \n"
+			"cld             \n"
+			/* setup registers for kernel setup */
+			"movw %0, %%ds   \n"
+			"movw %0, %%es   \n"
+			"movw %0, %%fs   \n"
+			"movw %0, %%gs   \n"
+			"movw %0, %%ss   \n"
+			"movw %2, %%sp   \n"
+			/* push CS:IP */
+			"pushw %1        \n"
+			"pushw $0        \n"
+			/* now (implicitly) jump to CS:IP */
+			"lretw           \n"
+			:
+			: "rm" (ds), "rm" (cs), "rm" (sp)
+	);
+}
+
+/* hook INT 13 */
+/* called from ASM code in boot.S */
+void int19_handler_C()
+{
+	struct linuxboot_info info;
+
+	get_linuxboot_info(&info);
+
+	boot_linux(info.cs, info.ds, info.sp);
+}
diff --git a/linuxboot/signrom.c b/linuxboot/signrom.c
new file mode 100644
index 0000000..2f2a734
--- /dev/null
+++ b/linuxboot/signrom.c
@@ -0,0 +1,128 @@
+/*
+ * Extended Boot Option ROM
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corporation, 2007
+ *   Authors: Anthony Liguori <[EMAIL PROTECTED]>
+ *
+ * Copyright by Nguyen Anh Quynh <[EMAIL PROTECTED]>, 2008.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define BLOCK 512
+
+static long get_file_size(FILE *f)
+{
+	long where, size;
+
+	where = ftell(f);
+	fseek(f, 0, SEEK_END);
+	size = ftell(f);
+	fseek(f, where, SEEK_SET);
+
+	return size;
+}
+
+int main(int argc, char **argv)
+{
+	FILE *fin, *fout;
+	char buffer[BLOCK];
+	int i, j, size;
+	long rom_size;
+
+	uint8_t sum = 0;
+
+	if (argc != 3) {
+		printf("Usage: %s <ROM> <OUTPUT>\n", argv[0]);
+		return 1;
+	}
+
+	fin = fopen(argv[1], "rb");
+	fout = fopen(argv[2], "wb");
+
+	if (fin == NULL || fout == NULL) {
+		fprintf(stderr, "Could not open input/output files\n");
+		return 1;
+	}
+
+	rom_size = get_file_size(fin);
+	if (rom_size == 0) {
+		fprintf(stderr, "Error: ROM size = 0?\n");
+		return 1;
+	}
+
+	/* set rom_size to blocks of 512 bytes */
+	rom_size = (rom_size/512) + 1;
+
+	/* read all data in ROM image, except the last block */
+	for (i = 0; i < rom_size - 1; i ++) {
+		memset(buffer, 0, sizeof(buffer));
+
+		size = fread(buffer, BLOCK, 1, fin);
+		if (size == 1) {
+			if (i == 0) {
+				/* first block, lets set ROM size */
+				buffer[2] = (uint8_t)rom_size;
+			}
+
+			for (j = 0; j < BLOCK; j++)
+				sum += buffer[j];
+
+			if (fwrite(buffer, BLOCK, 1, fout) != 1) {
+				fprintf(stderr, "Write failed\n");
+				return 1;
+			}
+		}
+		else {
+			fprintf(stderr, "Failed to read from input file\n");
+			return 1;
+		}
+	}
+
+	/* now read last block of ROM image */
+	memset(buffer, 0, sizeof(buffer));
+	size = fread(buffer, 1, BLOCK, fin);
+	if (ferror(fin)) {
+		fprintf(stderr, "Failed to read from input file\n");
+		return 1;
+	}
+
+	if (rom_size == 1)
+		/* set ROM size */
+		buffer[2] = (uint8_t)rom_size;
+
+	for (i = 0; i < size; i++)
+		sum += buffer[i];
+
+	/* set checksum in final byte */
+	buffer[BLOCK - 1] = -sum;
+
+	if (fwrite(buffer, BLOCK, 1, fout) != 1) {
+		fprintf(stderr, "Failed to write to output file\n");
+		return 1;
+	}
+
+	fclose(fin);
+	fclose(fout);
+
+	return 0;
+}
diff --git a/linuxboot/util.h b/linuxboot/util.h
new file mode 100644
index 0000000..7f859d8
--- /dev/null
+++ b/linuxboot/util.h
@@ -0,0 +1,69 @@
+/*
+ * util.h
+ *
+ * Copyright (C) 2008, Nguyen Anh Quynh <[EMAIL PROTECTED]>
+ *
+ * Some code is lifted from the legacybios project by Kevin O'Connor (http://www.linuxtogo.org/~kevin/)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __UTIL_H__
+#define __UTIL_H__
+
+#include <stdint.h>
+
+static inline void outw(uint16_t value, uint16_t port)
+{
+	asm volatile("outw %w0, %w1" : : "a"(value), "Nd"(port));
+}
+
+#define UREG(ER, R, RH, RL) union { uint32_t ER; 	\
+	struct { uint16_t R; uint16_t R ## _hi; };	\
+	struct {	\
+		uint8_t RL;	\
+		uint8_t RH;	\
+		uint8_t R ## _hilo;	\
+		uint8_t R ## _hihi;	\
+	};	\
+}
+
+/* Set of registers passed to INT 13 handler.
+ * These registers can be modified on return. */
+struct iregs {
+	uint16_t ds;
+	uint16_t es;
+	UREG(edi, di, di_hi, di_lo);
+	UREG(esi, si, si_hi, si_lo);
+	UREG(ebx, bx, bh, bl);
+	UREG(edx, dx, dh, dl);
+	UREG(ecx, cx, ch, cl);
+	UREG(eax, ax, ah, al);
+	uint16_t ip;
+	uint16_t cs;
+	uint16_t flags;
+} __attribute__((packed));
+
+static inline void *memcpy(void * dest, void *src, unsigned int count)
+{
+	char *tmp = (char *)dest, *s = (char *)src;
+
+	while (count--)
+		*tmp++ = *s++;
+
+	return dest;
+}
+
+#endif
diff --git a/qemu/Makefile b/qemu/Makefile
index a3054b4..3722b5e 100644
--- a/qemu/Makefile
+++ b/qemu/Makefile
@@ -195,7 +195,7 @@ endif
 	mkdir -p "$(DESTDIR)$(datadir)"
 	set -e; for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
 		video.x openbios-sparc32 pxe-ne2k_pci.bin \
-		pxe-rtl8139.bin pxe-pcnet.bin pxe-e1000.bin extboot.bin \
+		pxe-rtl8139.bin pxe-pcnet.bin pxe-e1000.bin extboot.bin linuxboot.bin \
 		bamboo.dtb; \
         do \
 		$(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
@@ -302,6 +302,7 @@ tarbin:
 	$(datadir)/pxe-rtl8139.bin \
         $(datadir)/pxe-pcnet.bin \
 	$(datadir)/extboot.bin \
+	$(datadir)/linuxboot.bin \
 	$(docdir)/qemu-doc.html \
 	$(docdir)/qemu-tech.html \
 	$(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1
diff --git a/qemu/Makefile.target b/qemu/Makefile.target
index 2fc2988..6a6d21b 100644
--- a/qemu/Makefile.target
+++ b/qemu/Makefile.target
@@ -591,7 +591,7 @@ ifeq ($(TARGET_BASE_ARCH), i386)
 OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o
 OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
 OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o
-OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o extboot.o
+OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o extboot.o linuxboot.o
 ifeq ($(USE_KVM_PIT), 1)
 OBJS+= i8254-kvm.o
 endif
diff --git a/qemu/hw/linuxboot.c b/qemu/hw/linuxboot.c
new file mode 100644
index 0000000..e6b7e4f
--- /dev/null
+++ b/qemu/hw/linuxboot.c
@@ -0,0 +1,39 @@
+/*
+ * linuxboot.c
+ * Linux Boot Option ROM.
+ *
+ * Copyright (C) Nguyen Anh Quynh <[EMAIL PROTECTED]>, 2008.
+ *
+ * This code is released under the GNU GPL license version 2. 
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "hw.h"
+#include "pc.h"
+
+/* Extended Boot ROM suport */
+
+struct linuxboot_info {
+	/* uint16_t request; */
+	uint16_t cs;        /* CS segment */
+	uint16_t ds;        /* DS segment */
+	uint16_t sp;        /* SP reg */
+};
+
+#define LINUXBOOT_PORT 0x407
+
+static void linuxboot_write(void *opaque, uint32_t addr, uint32_t value)
+{
+    struct linuxboot_info *info = (void *)(phys_ram_base + ((value & 0xFFFF) << 4));
+
+	info->cs = kernel_setup_cs;
+	info->ds = kernel_setup_ds;
+	info->sp = kernel_setup_sp;
+
+	cpu_physical_memory_set_dirty((value & 0xFFFF) << 4);
+}
+
+void linuxboot_init()
+{
+    register_ioport_write(LINUXBOOT_PORT, 1, 2, linuxboot_write, NULL);
+}
diff --git a/qemu/hw/pc.c b/qemu/hw/pc.c
index ae87ab9..fdde4cd 100644
--- a/qemu/hw/pc.c
+++ b/qemu/hw/pc.c
@@ -41,6 +41,7 @@
 #define VGABIOS_FILENAME "vgabios.bin"
 #define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
 #define EXTBOOT_FILENAME "extboot.bin"
+#define LINUXBOOT_FILENAME "linuxboot.bin"
 
 /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables.  */
 #define ACPI_DATA_SIZE       0x10000
@@ -492,6 +493,8 @@ static long get_file_size(FILE *f)
     return size;
 }
 
+uint16_t kernel_setup_cs, kernel_setup_ds, kernel_setup_sp;
+
 static void load_linux(const char *kernel_filename,
 		       const char *initrd_filename,
 		       const char *kernel_cmdline)
@@ -638,11 +641,12 @@ static void load_linux(const char *kernel_filename,
     /* generate bootsector to set up the initial register state */
     real_seg = (real_addr-phys_ram_base) >> 4;
     seg[0] = seg[2] = seg[3] = seg[4] = seg[4] = real_seg;
-    seg[1] = real_seg+0x20;	/* CS */
+	kernel_setup_ds = real_seg;
+    kernel_setup_cs = seg[1] = real_seg+0x20;	/* CS */
     memset(gpr, 0, sizeof gpr);
-    gpr[4] = cmdline_addr-real_addr-16;	/* SP (-16 is paranoia) */
+    kernel_setup_sp = gpr[4] = cmdline_addr-real_addr-16;	/* SP (-16 is paranoia) */
 
-    generate_bootsect(gpr, seg, 0);
+    //generate_bootsect(gpr, seg, 0);
 }
 
 static void main_cpu_reset(void *opaque)
@@ -903,6 +907,14 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
     for (i = 0; i < nb_option_roms; i++)
 	opt_rom_offset += load_option_rom(option_rom[i], opt_rom_offset);
 
+	/* linuxboot option ROM also intercepts int19, but never call original int19,
+	 * so it must be loaded before extboot! */
+    if (linux_boot) {
+	snprintf(buf, sizeof(buf), "%s/%s", bios_dir, LINUXBOOT_FILENAME);
+	opt_rom_offset += load_option_rom(buf, opt_rom_offset);
+	fprintf(stderr, "linuxboot ROM loaded at 0x%x\n", opt_rom_offset);
+	}
+
     if (extboot_drive != -1) {
 	snprintf(buf, sizeof(buf), "%s/%s", bios_dir, EXTBOOT_FILENAME);
 	opt_rom_offset += load_option_rom(buf, opt_rom_offset);
@@ -931,8 +943,10 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
 
     bochs_bios_init();
 
-    if (linux_boot)
+    if (linux_boot) {
 	load_linux(kernel_filename, initrd_filename, kernel_cmdline);
+	linuxboot_init();
+	}
 
     cpu_irq = qemu_allocate_irqs(pic_irq_request, first_cpu, 1);
     i8259 = i8259_init(cpu_irq[0]);
diff --git a/qemu/hw/pc.h b/qemu/hw/pc.h
index f26fcb6..d86ecfd 100644
--- a/qemu/hw/pc.h
+++ b/qemu/hw/pc.h
@@ -158,7 +158,10 @@ void *virtio_blk_init(PCIBus *bus, uint16_t vendor, uint16_t device,
 		      BlockDriverState *bs);
 
 /* extboot.c */
-
 void extboot_init(BlockDriverState *bs, int cmd);
 
+/* linux_boot */
+uint16_t kernel_setup_cs, kernel_setup_ds, kernel_setup_sp;
+void linuxboot_init(void);
+
 #endif
-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to