commit f4f1178898c8a4bbbc0a432354dbcc56353099c3
Author: Nguyen Anh Quynh
Date: Mon Apr 21 12:27:47 2008 +0900
Linuxboot Option ROM support.
Signed-off-by: Nguyen Anh Quynh
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
+
+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 , 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
+ *
+ * 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
+
+// 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 , 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
+ *
+ * Copyright by Nguyen Anh Quynh , 2008.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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