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