This patch replaces the current assembly code of Extboot option rom
with new C code. Patch is against kvm-66.
This version returns an error code in case int 13 handler cannot
handle a requested function.
Signed-off-by: Nguyen Anh Quynh <[EMAIL PROTECTED]>
# diffstat extboot3.diff
b/extboot/Makefile | 67 ++--
b/extboot/boot.S | 119 ++++++++
b/extboot/farvar.h | 113 ++++++++
b/extboot/rom.c | 366 ++++++++++++++++++++++++++
b/extboot/signrom.c | 83 ++++--
b/extboot/util.h | 89 ++++++
extboot/extboot.S | 705 ----------------------------------------------------
7 files changed, 786 insertions(+), 756 deletions(-)
commit bd0c778b70bbbcc5f120478278a965f87b8af7f4
Author: Nguyen Anh Quynh <[EMAIL PROTECTED]>
Date: Thu Apr 17 10:22:00 2008 +0900
Extboot Option ROM rewritten in C
Signed-off-by: Nguyen Anh Quynh <[EMAIL PROTECTED]>
diff --git a/extboot/Makefile b/extboot/Makefile
index ab2dae7..8ac5b7b 100644
--- a/extboot/Makefile
+++ b/extboot/Makefile
@@ -1,35 +1,34 @@
-OBJCOPY=objcopy
-
-# from kernel sources - scripts/Kbuild.include
-# try-run
-# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
-# Exit code chooses option. "$$TMP" is can be used as temporary file and
-# is automatically cleaned up.
-try-run = $(shell set -e; \
- TMP="$(TMPOUT).$$$$.tmp"; \
- if ($(1)) >/dev/null 2>&1; \
- then echo "$(2)"; \
- else echo "$(3)"; \
- fi; \
- rm -f "$$TMP")
-
-# cc-option-yn
-# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
-cc-option-yn = $(call try-run,\
- $(CC) $(KBUILD_CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",y,n)
-
-CFLAGS = -Wall -Wstrict-prototypes -Werror -fomit-frame-pointer -fno-builtin
-ifeq ($(call cc-option-yn,-fno-stack-protector),y)
-CFLAGS += -fno-stack-protector
-endif
-
-all: extboot.bin
+# Makefile for extboot Option ROM
+# Nguyen Anh Quynh <[EMAIL PROTECTED]>
-%.o: %.S
- $(CC) $(CFLAGS) -o $@ -c $<
+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 extboot.bin
+
+.PHONY: install
+install: extboot.bin
+ cp extboot.bin $(INSTALLDIR)
+
+.PHONY: save
+save:
+ mv $(INSTALLDIR)/extboot.bin $(INSTALLDIR)/extboot.bin.org
+
+.PHONY: clean
+clean:
+ $(RM) *.o *.img *.bin signrom *~
-extboot.img: extboot.o
- $(LD) --oformat binary -Ttext 0 -o $@ $<
+extboot.img: boot.o rom.o
+ $(LD) --oformat binary -Ttext 0 $^ -o $@
extboot.bin: extboot.img signrom
./signrom extboot.img extboot.bin
@@ -37,5 +36,9 @@ extboot.bin: extboot.img signrom
signrom: signrom.c
$(CC) -o $@ -g -Wall $^
-clean:
- $(RM) *.o *.img *.bin signrom *~
+%.o: %.c
+ $(CC) $(CCFLAGS) -c $<
+
+%.o: %.S
+ $(CC) $(CCFLAGS) -c $<
+
diff --git a/extboot/boot.S b/extboot/boot.S
new file mode 100644
index 0000000..bc7e20c
--- /dev/null
+++ b/extboot/boot.S
@@ -0,0 +1,119 @@
+/*
+ * extboot.c
+ * Extended Boot Option ROM for QEMU.
+
+ * Copyright (C) by Nguyen Anh Quynh <[EMAIL PROTECTED]>, 2008.
+ *
+ * Based on the ASM version extboot.S of Anthony Liguori <[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.
+ */
+
+ .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
+ /* -fomit-frame-pointer might clobber %ebp */
+ pushl %ebp
+ call setup
+ popl %ebp
+ popw %es
+ popal
+ lretw
+
+ /* interrupt 19 handler */
+ .globl int19_handler
+ .extern int19_handler_C
+ .extern linux_boot
+ int19_handler:
+ pushal
+ /* %es is clobbered, so save it */
+ pushw %es
+ /* -fomit-frame-pointer might clobber %ebp */
+ pushl %ebp
+ call int19_handler_C
+ popl %ebp
+ popw %es
+ orw %ax, %ax /* Do we need to execute original INT 19? */
+ popal
+ jnz linux_boot /* No, just boot Linux kernel */
+ int $0x2b
+
+ /* interrupt 13 handler */
+ .globl int13_handler
+ .extern int13_handler_C
+int13_handler:
+ cmpb $0x80, %dl
+ /* only interested in 1st IDE HDD */
+ je 1f
+ /* call original int13 */
+ int $0x2c
+ iretw
+
+ 1:
+ /* Pass a set of registers to C code.
+ * These registers might be modified on return. */
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+ pushw %es
+ pushw %ds
+ /* Set %ds = %ss */
+ movw %ss, %ax
+ movw %ax, %ds
+ /* Backup %esp, then clear high bits */
+ movl %esp, %ebx
+ movzwl %sp, %esp
+ /* We use -regparm(1), so %eax points to struct ibregs */
+ movl %esp, %eax
+ /* -fomit-frame-pointer might clobber %ebp */
+ pushl %ebp
+ calll int13_handler_C
+ popl %ebp
+ /* Restore %esp (including high bits) */
+ movl %ebx, %esp
+ /* Restore registers. These registers might be modified in C code */
+ popw %ds
+ popw %es
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %edx
+ popl %ecx
+ popl %eax
+ iretw
+
+ .globl linux_boot
+linux_boot:
+ cli
+ cld
+ mov $0x9000, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+ mov %ax, %ss
+ mov $0x8ffe, %sp
+ ljmp $0x9000 + 0x20, $0
diff --git a/extboot/extboot.S b/extboot/extboot.S
deleted file mode 100644
index 9eb9333..0000000
--- a/extboot/extboot.S
+++ /dev/null
@@ -1,705 +0,0 @@
-/*
- * 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]>
- */
-
-.code16
-.text
- .global _start
-_start:
- .short 0xaa55
- .byte (_end - _start) / 512
- push %ax
- push %bx
- push %cx
- push %dx
- push %ds
-
- /* setup ds so we can access the IVT */
- xor %ax, %ax
- mov %ax, %ds
-
- /* save old int 19 at int 2b */
- mov $(0x19 * 4), %bx
- mov 0(%bx), %ax
- mov 2(%bx), %cx
-
- mov $(0x2b * 4), %bx
- mov %ax, 0(%bx)
- mov %cx, 2(%bx)
-
- /* install out int 19 handler */
- mov $(0x19 * 4), %bx
- mov $int19_handler, %ax
- mov %ax, 0(%bx)
- mov %cs, 2(%bx)
-
- pop %ds
- pop %dx
- pop %cx
- pop %bx
- pop %ax
- lret
-
-int19_handler:
- push %ax
- push %bx
- push %cx
- push %dx
- push %ds
-
- movw $0x404, %dx
- inb %dx, %al
- cmp $1, %al
- je 1f
- cmp $2, %al
- je 2f
- jmp 3f
-
-1: /* hook int13: intb(0x404) == 1 */
- /* setup ds to access IVT */
- xor %ax, %ax
- mov %ax, %ds
-
- /* save old int 13 to int 2c */
- mov $(0x13 * 4), %bx
- mov 0(%bx), %ax
- mov 2(%bx), %cx
-
- mov $(0x2c * 4), %bx
- mov %ax, 0(%bx)
- mov %cx, 2(%bx)
-
- /* install our int 13 handler */
- mov $(0x13 * 4), %bx
- mov $int13_handler, %ax
-
- mov %ax, 0(%bx)
- mov %cs, 2(%bx)
- jmp 3f
-
-2: /* linux boot: intb(0x404) == 2 */
- cli
- cld
- mov $0x9000, %ax
- mov %ax, %ds
- mov %ax, %es
- mov %ax, %fs
- mov %ax, %gs
- mov %ax, %ss
- mov $0x8ffe, %sp
- ljmp $0x9000 + 0x20, $0
-
-3: /* fall through: inb(0x404) == 0 */
- pop %ds
- pop %dx
- pop %cx
- pop %bx
- pop %ax
- int $0x2b
-
-#define FLAGS_CF 0x01
-
-.macro clc
- push %ax
- pushf
- pop %ax
- and $(~FLAGS_CF), %ax
- push %ax
- popf
- pop %ax
-.endm
-
-.macro stc
- push %ax
- pushf
- pop %ax
- or $(FLAGS_CF), %ax
- push %ax
- popf
- pop %ax
-.endm
-
-/* we clobber %bx */
-.macro alloca size
- push %ds
- push %bp
- mov %sp, %bp /* remember the current stack position */
-
- mov %ss, %bx
- mov %bx, %ds
-
- sub \size, %sp
- and $(~0x0F), %sp
- mov %sp, %bx
-
- push %bp
- mov 0(%bp), %bp
-.endm
-
-/* we clobber %bp */
-.macro allocbpa size
- mov %sp, %bp /* remember the current stack position */
- sub \size, %sp
- and $(~0x0F), %sp
- push %bp
- mov %sp, %bp
- add $2, %bp
-.endm
-
-.macro freea
- pop %sp
- add $2, %sp
- pop %ds
-.endm
-
-.macro freebpa
- pop %sp
-.endm
-
-.macro dump reg
- push %ax
- push %dx
-
- mov \reg, %ax
- mov $0x406, %dx
- outw %ax, %dx
-
- pop %dx
- pop %ax
-.endm
-
-.macro callout value
- push %bp
- push %bx
- mov %sp, %bp
- alloca $16
- push %ax
- push %dx
-
- mov %ax, 0(%bx) /* ax */
- mov 0(%bp), %ax /* bx */
- mov %ax, 2(%bx)
- mov %cx, 4(%bx) /* cx */
- mov %dx, 6(%bx) /* dx */
- mov %si, 8(%bx) /* si */
- mov %ds, 10(%bx) /* ds */
- mov %es, 12(%bx) /* ds */
- movw \value, 14(%bx) /* value */
-
- mov %bx, %ax
- shr $4, %ax
- mov %ds, %dx
- add %dx, %ax
-
- mov $0x407, %dx
- outw %ax, %dx
-
- pop %dx
- pop %ax
- freea
- pop %bx
- pop %bp
-.endm
-
-send_command:
- push %bp
- mov %sp, %bp
- push %ax
- push %bx
- push %dx
-
- mov 4(%bp), %ax
- shr $4, %ax
- and $0x0FFF, %ax
- mov %ss, %bx
- add %bx, %ax
-
- mov $0x405, %dx
- outw %ax, %dx
-
- pop %dx
- pop %bx
- pop %ax
- pop %bp
-
- push %ax
- mov 2(%bx), %ax
- pop %ax
-
- ret
-
-add32: /* lo, hi, lo, hi */
- push %bp
- mov %sp, %bp
-
- movw 4(%bp), %cx /* hi */
- movw 6(%bp), %dx /* lo */
-
- add 10(%bp), %dx
- jnc 1f
- add $1, %cx
-1: add 8(%bp), %cx
-
- pop %bp
- ret
-
-mul32: /* lo, hi, lo, hi */
- /* 10(%bp), 8(%bp), 6(%bp), 4(%bp) */
- push %bp
- mov %sp, %bp
- push %ax
- push %bx
-
- xor %cx, %cx
- xor %dx, %dx
-
- /* for (i = 0; i < 16;) */
- xor %bx, %bx
-0:
- cmp $16, %bx
- jge 2f
-
- mov 6(%bp), %ax
- and $1, %ax
- cmp $1, %ax
- jne 1f
- push 10(%bp)
- push 8(%bp)
- push %dx
- push %cx
- call add32
- add $8, %sp
-1:
- shlw $1, 8(%bp)
- movw 10(%bp), %ax
- and $0x8000, %ax
- cmp $0x8000, %ax
- jne 1f
- orw $1, 8(%bp)
-1:
- shlw $1, 10(%bp)
- shrw $1, 6(%bp)
-
- /* i++) { */
- add $1, %bx
- jmp 0b
-
-2:
- pop %bx
- pop %ax
- pop %bp
- ret
-
-disk_reset:
- movb $0, %ah
- clc
- ret
-
-/* this really should be a function, not a macro but i'm lazy */
-.macro read_write_disk_sectors cmd
- push %ax
- push %bx
- push %cx
- push %dx
- push %si
-
- push %bp
- sub $10, %sp
- mov %sp, %bp
-
- /* save nb_sectors */
- mov %al, 6(%bp)
- movb $0, 7(%bp)
-
- /* save buffer */
- mov %bx, 8(%bp)
-
- /* cylinders */
- xor %ax, %ax
- mov %cl, %al
- shl $2, %ax
- and $0x300, %ax
- mov %ch, %al
- mov %ax, 0(%bp)
-
- /* heads */
- xor %ax, %ax
- mov %dh, %al
- mov %ax, 2(%bp)
-
- /* sectors - 1 */
- xor %ax, %ax
- mov %cl, %al
- and $0x3F, %al
- sub $1, %ax
- mov %ax, 4(%bp)
-
- alloca $16
-
- movw $0, 0(%bx) /* read c,h,s */
- push %bx
- call send_command
- add $2, %sp
-
- mov 6(%bx), %ax /* total_sectors */
- mov 2(%bp), %si /* *= heads */
- mul %si
- add 4(%bp), %ax /* += sectors - 1 */
-
- push 4(%bx) /* total_heads */
- push $0
- push 6(%bx) /* total_sectors */
- push $0
- call mul32
- add $8, %sp
-
- push 0(%bp) /* cylinders */
- push $0
- push %dx
- push %cx
- call mul32
- add $8, %sp
-
- add %ax, %dx
- jnc 1f
- add $1, %cx
-1:
- freea
-
- alloca $16
-
- movw \cmd, 0(%bx) /* read */
- movw 6(%bp), %ax /* nb_sectors */
- movw %ax, 2(%bx)
- movw %es, 4(%bx) /* segment */
- movw 8(%bp), %ax /* offset */
- mov %ax, 6(%bx)
- movw %dx, 8(%bx) /* sector */
- movw %cx, 10(%bx)
- movw $0, 12(%bx)
- movw $0, 14(%bx)
-
- push %bx
- call send_command
- add $2, %sp
-
- freea
-
- add $10, %sp
- pop %bp
-
- pop %si
- pop %dx
- pop %cx
- pop %bx
- pop %ax
-
- mov $0, %ah
- clc
- ret
-.endm
-
-read_disk_sectors:
- read_write_disk_sectors $0x01
-
-write_disk_sectors:
- read_write_disk_sectors $0x02
-
-read_disk_drive_parameters:
- push %bx
-
- /* allocate memory for packet, pointer gets returned in bx */
- alloca $16
-
- /* issue command */
- movw $0, 0(%bx) /* cmd = 0, read c,h,s */
- push %bx
- call send_command
- add $2, %sp
-
- /* normalize sector value */
- movb 6(%bx), %cl
- andb $0x3F, %cl
- movb %cl, 6(%bx)
-
- /* normalize cylinders */
- subw $2, 2(%bx)
-
- /* normalize heads */
- subw $1, 4(%bx)
-
- /* return code */
- mov $0, %ah
-
- /* cylinders */
- movb 2(%bx), %ch
- movb 3(%bx), %cl
- shlb $6, %cl
- andb $0xC0, %cl
-
- /* sectors */
- orb 6(%bx), %cl
-
- /* heads */
- movb 4(%bx), %dh
-
- /* drives */
- movb $1, %dl
-
- /* status */
- mov $0, %ah
-
- freea
-
- pop %bx
-
- /* do this last since it's the most sensitive */
- clc
- ret
-
-alternate_disk_reset:
- movb $0, %ah
- clc
- ret
-
-read_disk_drive_size:
- push %bx
- alloca $16
-
- movw $0, 0(%bx) /* cmd = 0, read c,h,s */
- push %bx
- call send_command
- add $2, %sp
-
- /* cylinders - 1 to cx:dx */
- mov 2(%bx), %dx
- xor %cx, %cx
- sub $1, %dx
-
- /* heads */
- push 4(%bx)
- push $0
- push %dx
- push %cx
- call mul32
- add $8, %sp
-
- /* sectors */
- push 6(%bx)
- push $0
- push %dx
- push %cx
- call mul32
- add $8, %sp
-
- /* status */
- mov $3, %ah
-
- freea
- pop %bx
-
- clc
- ret
-
-check_if_extensions_present:
- mov $0x30, %ah
- mov $0xAA55, %bx
- mov $0x07, %cx
- clc
- ret
-
-.macro extended_read_write_sectors cmd
- cmpb $10, 0(%si)
- jg 1f
- mov $1, %ah
- stc
- ret
-1:
- push %ax
- push %bp
- allocbpa $16
-
- movw \cmd, 0(%bp) /* read */
- movw 2(%si), %ax /* nb_sectors */
- movw %ax, 2(%bp)
- movw 4(%si), %ax /* offset */
- movw %ax, 6(%bp)
- movw 6(%si), %ax /* segment */
- movw %ax, 4(%bp)
- movw 8(%si), %ax /* block */
- movw %ax, 8(%bp)
- movw 10(%si), %ax
- movw %ax, 10(%bp)
- movw 12(%si), %ax
- movw %ax, 12(%bp)
- movw 14(%si), %ax
- movw %ax, 14(%bp)
-
- push %bp
- call send_command
- add $2, %sp
-
- freebpa
- pop %bp
- pop %ax
-
- mov $0, %ah
- clc
- ret
-.endm
-
-extended_read_sectors:
- extended_read_write_sectors $0x01
-
-extended_write_sectors:
- extended_read_write_sectors $0x02
-
-get_extended_drive_parameters:
- push %ax
- push %bp
- push %cx
- push %dx
-
- allocbpa $16
-
- movw $0, 0(%bp) /* read c,h,s */
- push %bp
- call send_command
- add $2, %sp
-
- /* write size */
- movw $26, 0(%si)
-
- /* set flags to 2 */
- movw $2, 2(%si)
-
- /* cylinders */
- mov 2(%bp), %ax
- mov %ax, 4(%si)
- xor %ax, %ax
- mov %ax, 6(%si)
-
- /* heads */
- mov 4(%bp), %ax
- mov %ax, 8(%si)
- xor %ax, %ax
- mov %ax, 10(%si)
-
- /* sectors */
- mov 6(%bp), %ax
- mov %ax, 12(%si)
- xor %ax, %ax
- mov %ax, 14(%si)
-
- /* set total number of sectors */
- mov 8(%bp), %ax
- mov %ax, 16(%si)
- mov 10(%bp), %ax
- mov %ax, 18(%si)
- mov 12(%bp), %ax
- mov %ax, 20(%si)
- mov 14(%bp), %ax
- mov %ax, 22(%si)
-
- /* number of bytes per sector */
- movw $512, 24(%si)
-
- freebpa
-
- pop %dx
- pop %cx
- pop %bp
- pop %ax
-
- mov $0, %ah
- clc
- ret
-
-terminate_disk_emulation:
- mov $1, %ah
- stc
- ret
-
-int13_handler:
- cmp $0x80, %dl
- je 1f
- int $0x2c
- iret
-1:
- cmp $0x0, %ah
- jne 1f
- call disk_reset
- iret
-1:
- cmp $0x2, %ah
- jne 1f
- call read_disk_sectors
- iret
-1:
- cmp $0x8, %ah
- jne 1f
- call read_disk_drive_parameters
- iret
-1:
- cmp $0x15, %ah
- jne 1f
- call read_disk_drive_size
- iret
-1:
- cmp $0x41, %ah
- jne 1f
- call check_if_extensions_present
- iret
-1:
- cmp $0x42, %ah
- jne 1f
- call extended_read_sectors
- iret
-1:
- cmp $0x48, %ah
- jne 1f
- call get_extended_drive_parameters
- iret
-1:
- cmp $0x4b, %ah
- jne 1f
- call terminate_disk_emulation
- iret
-1:
- cmp $0x0d, %ah
- jne 1f
- call alternate_disk_reset
- iret
-1:
- cmp $0x03, %ah
- jne 1f
- call write_disk_sectors
- iret
-1:
- cmp $0x43, %ah
- jne 1f
- call extended_write_sectors
- iret
-1:
- int $0x18 /* boot failed */
- iret
-
-.align 512, 0
-_end:
diff --git a/extboot/farvar.h b/extboot/farvar.h
new file mode 100644
index 0000000..b0c7be7
--- /dev/null
+++ b/extboot/farvar.h
@@ -0,0 +1,113 @@
+// Code to access multiple segments within gcc.
+//
+// Copyright (C) 2008 Kevin O'Connor <[EMAIL PROTECTED]>
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+#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_ES, __segment_CS, __segment_DS, __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 %b0, %%" #SEG ":%1" : \
+ : "Q"(value), "m"(var), "m"(__segment_ ## SEG))
+#define __WRITE16_SEG(SEG, var, value) \
+ __asm__("movw %w0, %%" #SEG ":%1" : \
+ : "r"(value), "m"(var), "m"(__segment_ ## SEG))
+#define __WRITE32_SEG(SEG, var, value) \
+ __asm__("movl %0, %%" #SEG ":%1" : \
+ : "r"(value), "m"(var), "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/extboot/rom.c b/extboot/rom.c
new file mode 100644
index 0000000..f70c99e
--- /dev/null
+++ b/extboot/rom.c
@@ -0,0 +1,366 @@
+/*
+ * extboot.c
+ * Extended Boot Option ROM for QEMU.
+ *
+ * Copyright (C) by Nguyen Anh Quynh <[EMAIL PROTECTED]>, 2008.
+ *
+ * Based on the ASM version extboot.S of Anthony Liguori <[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.
+ */
+
+#include "util.h"
+#include "farvar.h"
+
+asm (".code16gcc");
+
+union extboot_cmd {
+ uint16_t type;
+ struct {
+ uint16_t type;
+ uint16_t cylinders;
+ uint16_t heads;
+ uint16_t sectors; /* sectors per track */
+ uint64_t nb_sectors; /* total number of sectors in drive */
+ } query_geometry;
+ struct {
+ uint16_t type;
+ uint16_t nb_sectors;
+ uint16_t segment;
+ uint16_t offset;
+ uint64_t sector;
+ } xfer;
+};
+
+#define EXTBOOT_READ_PORT 0x404
+#define EXTBOOT_WRITE_PORT 0x405
+
+#define MODE_READ 1
+#define MODE_WRITE 2
+
+#define INT13_INVALID_FUNC_PARAM 1
+
+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()
+{
+ uint16_t seg, off;
+
+ /* save original INT 19 into -unused- INT 2b */
+ seg = GET_IVT_ENTRY(0x19, segment);
+ off = GET_IVT_ENTRY(0x19, offset);
+ SET_IVT_ENTRY(0x2b, segment, seg);
+ SET_IVT_ENTRY(0x2b, offset, off);
+
+ /* install our INT 19 handler */
+ extern void int19_handler;
+ seg = GET_SEG(CS);
+ SET_IVT_ENTRY(0x19, segment, seg);
+ SET_IVT_ENTRY(0x19, offset, (uint16_t)&int19_handler);
+}
+
+/* send command to QEMU via a dedicated IO port */
+static void send_command(union extboot_cmd *cmd)
+{
+ uint16_t seg;
+ char tmp[16 + sizeof(*cmd)], *p;
+
+ /* align to 16 */
+ p = (char *)(((uint32_t)tmp + 0xF) & ~0xF);
+ memcpy(p, cmd, sizeof(*cmd));
+
+ /* send segment contained cmd to QEMU */
+ seg = ((uint32_t)p >> 4) + GET_SEG(SS);
+ outw(seg, EXTBOOT_WRITE_PORT);
+
+ /* now copy back the result to cmd */
+ memcpy(cmd, p, sizeof(*cmd));
+}
+
+/* interrupt returns succesfully */
+static void set_result_ok(struct iregs *regs, uint8_t status)
+{
+ /* set status in AH */
+ regs->ah = status;
+
+ /* succesfull, clear CF */
+ set_cf(regs, 0);
+}
+
+/* interrupt returns with failure */
+static void set_result_fail(struct iregs *regs, uint8_t status)
+{
+ /* set status in AH */
+ regs->ah = status;
+
+ /* set CF to indicate failure */
+ set_cf(regs, 1);
+}
+
+static void reset_disk(struct iregs *regs)
+{
+ set_result_ok(regs, 0);
+}
+
+/* mode == 1: read, mode ==2: write */
+static void read_write_sectors(struct iregs *regs, int mode)
+{
+ union extboot_cmd cmd;
+ uint8_t num_sectors = regs->al;
+ uint16_t buffer_offset = regs->bx;
+ uint16_t cylinder = regs->ch | ((regs->cl << 2) & 0x300);
+ uint8_t head = regs->dh;
+ uint8_t start_sector = (regs->cl & 0x3F) - 1;
+
+ /* query drive info */
+ cmd.type = 0;
+ send_command(&cmd);
+
+ /* convert chs to lba */
+ uint64_t lba =
+ (cylinder*cmd.query_geometry.heads + head)*cmd.query_geometry.sectors +
+ start_sector;
+
+ cmd.xfer.type = mode;
+ cmd.xfer.nb_sectors = num_sectors;
+ cmd.xfer.segment = regs->es;
+ cmd.xfer.offset = buffer_offset;
+ cmd.xfer.sector = lba;
+ send_command(&cmd);
+
+ /* everything is OK */
+ set_result_ok(regs, 0);
+}
+
+/* mode == 1: read, mode ==2: write */
+static void extend_read_write_sectors(struct iregs *regs, int mode)
+{
+ union extboot_cmd cmd;
+ struct disk_addr_packet {
+ uint8_t size;
+ uint8_t _r; /* reserved */
+ uint16_t blocks; /* number of blocks to transfer */
+ uint16_t offset;
+ uint16_t segment;
+ uint32_t lba_lo;
+ uint32_t lba_hi;
+ } PACKED;
+#define GET_DISK_ADDR_PACKET(var) \
+ GET_FARVAR((regs->ds), ((struct disk_addr_packet *)(regs->si+0))->var)
+
+ /*
+ * extern void copy_to_ss(void *, uint16_t, uint16_t, uint16_t);
+ * copy_to_ss(&packet, regs->ds, regs->si, sizeof(packet));
+ */
+ uint8_t packet_size = GET_DISK_ADDR_PACKET(size);
+ uint16_t packet_blocks = GET_DISK_ADDR_PACKET(blocks);
+ uint16_t packet_offset = GET_DISK_ADDR_PACKET(offset);
+ uint16_t packet_segment = GET_DISK_ADDR_PACKET(segment);
+ uint32_t lba_lo = GET_DISK_ADDR_PACKET(lba_lo);
+ uint32_t lba_hi = GET_DISK_ADDR_PACKET(lba_hi);
+ uint64_t packet_lba = ((uint64_t)lba_hi << 32) | lba_lo;
+
+ if (packet_size != sizeof(struct disk_addr_packet)) {
+ /* wrong packet size */
+ set_result_fail(regs, INT13_INVALID_FUNC_PARAM);
+ return;
+ }
+
+ cmd.xfer.type = mode;
+ cmd.xfer.nb_sectors = packet_blocks;
+ cmd.xfer.segment = packet_segment;
+ cmd.xfer.offset = packet_offset;
+ cmd.xfer.sector = packet_lba;
+ send_command(&cmd);
+
+ /* everything is OK */
+ set_result_ok(regs, 0);
+}
+
+static void get_drive_param(struct iregs *regs)
+{
+ union extboot_cmd cmd;
+
+ /* query drive info */
+ cmd.type = 0;
+ send_command(&cmd);
+
+ /* normalize sectors value */
+ cmd.query_geometry.sectors &= 0x3F;
+ /* normalize cylinders value: 0 based, last sector not used */
+ cmd.query_geometry.cylinders -= 2;
+ /* normalize heads value */
+ cmd.query_geometry.heads--;
+
+ regs->ch = cmd.query_geometry.cylinders & 0xFF;
+ regs->cl = cmd.query_geometry.sectors | ((cmd.query_geometry.cylinders >> 2) & 0xC0);
+ regs->dh = cmd.query_geometry.heads & 0xFF;
+ regs->dl = 1; /* only 1 drive */
+ regs->al = 0;
+
+ /* everything is OK */
+ set_result_ok(regs, 0);
+}
+
+static void get_extend_drive_param(struct iregs *regs)
+{
+ union extboot_cmd cmd;
+ struct extend_drive_param {
+ uint16_t size;
+ uint16_t flags;
+ uint32_t cylinders;
+ uint32_t heads;
+ uint32_t sectors_per_track; /* per track */
+ uint32_t total_sectors_lo;
+ uint32_t total_sectors_hi;
+ /* uint32_t total_sectors; */
+ uint16_t sector_size; /* in bytes */
+ } PACKED;
+#define SET_EXTEND_DRIVE_PARAM(var, value) \
+ SET_FARVAR((regs->ds), ((struct extend_drive_param *)(regs->si+0))->var, value)
+
+ /* query drive info */
+ cmd.type = 0;
+ send_command(&cmd);
+
+ /* We support Int13 extension 1.x format only */
+ SET_EXTEND_DRIVE_PARAM(size, sizeof(struct extend_drive_param));
+ /* flags: cylinder/head/sectors-per-track information is valid. See table 00274 */
+ SET_EXTEND_DRIVE_PARAM(flags, 2);
+ SET_EXTEND_DRIVE_PARAM(cylinders, cmd.query_geometry.cylinders);
+ SET_EXTEND_DRIVE_PARAM(heads, cmd.query_geometry.heads);
+ SET_EXTEND_DRIVE_PARAM(sectors_per_track, cmd.query_geometry.sectors);
+ SET_EXTEND_DRIVE_PARAM(total_sectors_hi, cmd.query_geometry.nb_sectors & 0xFFFFFFFF);
+ SET_EXTEND_DRIVE_PARAM(total_sectors_lo, cmd.query_geometry.nb_sectors >> 32);
+ SET_EXTEND_DRIVE_PARAM(sector_size, 512);
+
+ /* everything is OK */
+ set_result_ok(regs, 0);
+}
+
+static void get_drive_size(struct iregs *regs)
+{
+ union extboot_cmd cmd;
+
+ /* query drive info */
+ cmd.type = 0;
+ send_command(&cmd);
+
+ uint32_t total_sectors =
+ cmd.query_geometry.heads * (cmd.query_geometry.cylinders - 1) *
+ cmd.query_geometry.sectors;
+
+ /* cx:dx keeps total_sectors */
+ regs->dx = total_sectors & 0xFFFF;
+ regs->cx = total_sectors >> 16;
+
+ /* everything is OK */
+ set_result_ok(regs, 3);
+}
+
+static void check_extend_installation(struct iregs *regs)
+{
+ /* yes, extended function is supported */
+ regs->bx = 0xAA55;
+
+ /* cx keeps API support bitmap.
+ * Extended disk access + Removable + EDD funcs (Table 00271) */
+ regs->cx = 7; /* 0b111 */
+
+ /* everything is OK */
+ set_result_ok(regs, 0x30); /* EDD 3.0 extension */
+}
+
+static void terminate_disk_emu(struct iregs *regs)
+{
+ set_result_fail(regs, 1);
+}
+
+/* called from ASM code in boot.S */
+void __attribute__((regparm(1))) int13_handler_C(struct iregs *regs)
+{
+ switch (regs->ah) {
+ case 0x0:
+ /* reset disk */
+ return reset_disk(regs);
+ case 0x2:
+ /* read sectors */
+ return read_write_sectors(regs, MODE_READ);
+ case 0x3:
+ /* write sectors */
+ return read_write_sectors(regs, MODE_WRITE);
+ case 0x8:
+ /* query drive info */
+ return get_drive_param(regs);
+ case 0x0d:
+ /* alternate reset disk */
+ /* For now, do the same thing as our friend 0x0 above */
+ return reset_disk(regs);
+ case 0x15:
+ return get_drive_size(regs);
+ case 0x41:
+ /* installation check */
+ return check_extend_installation(regs);
+ case 0x42:
+ /* extended read sectors */
+ return extend_read_write_sectors(regs, MODE_READ);
+ case 0x43:
+ /* extended write sectors */
+ return extend_read_write_sectors(regs, MODE_WRITE);
+ case 0x48:
+ /* query extended drive info */
+ return get_extend_drive_param(regs);
+ case 0x4b:
+ return terminate_disk_emu(regs);
+ default:
+ /* invalid function */
+ return set_result_fail(regs, INT13_INVALID_FUNC_PARAM);
+ }
+}
+
+/* called from ASM code in boot.S */
+/* return 0 to fall-thru to original int19, 1 otherwise */
+int int19_handler_C()
+{
+ uint8_t x;
+
+ x = inb(EXTBOOT_READ_PORT);
+ switch (x) {
+ case 1: /* hook INT 13 */
+ /* save INT 13 into -unused- INT 2c */
+ SET_IVT_ENTRY(0x2c, segment, GET_IVT_ENTRY(0x13, segment));
+ SET_IVT_ENTRY(0x2c, offset, GET_IVT_ENTRY(0x13, offset));
+
+ /* install our INT 13 handler */
+ extern void int13_handler;
+ SET_IVT_ENTRY(0x13, segment, GET_SEG(CS));
+ SET_IVT_ENTRY(0x13, offset, (uint16_t)&int13_handler);
+ /* and call original INT 19 after getting back */
+ return 0;
+ case 2:
+ default:
+ /* do NOT call original INT 19 */
+ return 1;
+ }
+}
diff --git a/extboot/signrom.c b/extboot/signrom.c
index fe8d677..d4dad48 100644
--- a/extboot/signrom.c
+++ b/extboot/signrom.c
@@ -17,21 +17,42 @@
*
* 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[512], oldbuffer[512];
- int i, size, lag = 0;
+ 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]);
+ printf("Usage: %s <ROM> <OUTPUT>\n", argv[0]);
return 1;
}
@@ -43,31 +64,55 @@ int main(int argc, char **argv)
return 1;
}
- do {
- size = fread(buffer, 512, 1, fin);
+ 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) {
- for (i = 0; i < 512; i++)
- sum += buffer[i];
-
- if (lag) {
- if (fwrite(oldbuffer, 512, 1, fout) != 1) {
- fprintf(stderr, "Write failed\n");
- return 1;
- }
+ if (i == 0) {
+ /* first block, lets set ROM size */
+ buffer[2] = (uint8_t)rom_size;
}
- lag = 1;
- memcpy(oldbuffer, buffer, 512);
+
+ 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;
}
- } while (size == 1);
+ }
- if (size != 0) {
+ /* 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;
}
- oldbuffer[511] = -sum;
+ for (i = 0; i < size; i++)
+ sum += buffer[i];
+
+ /* set checksum in final byte */
+ buffer[BLOCK - 1] = -sum;
- if (fwrite(oldbuffer, 512, 1, fout) != 1) {
+ if (fwrite(buffer, BLOCK, 1, fout) != 1) {
fprintf(stderr, "Failed to write to output file\n");
return 1;
}
diff --git a/extboot/util.h b/extboot/util.h
new file mode 100644
index 0000000..4a1c142
--- /dev/null
+++ b/extboot/util.h
@@ -0,0 +1,89 @@
+/*
+ * util.h
+ *
+ * Copyright (C) 2008, Nguyen Anh Quynh <[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 __UTIL_H__
+#define __UTIL_H__
+
+#include <stdint.h>
+
+#define PACKED __attribute__((packed))
+
+static inline void outw(uint16_t value, uint16_t port)
+{
+ asm volatile("outw %w0, %w1" : : "a"(value), "Nd"(port));
+}
+
+static inline uint8_t inb(uint16_t port)
+{
+ uint8_t value;
+
+ asm volatile("inb %w1, %b0" : "=a"(value) : "Nd"(port));
+
+ return value;
+}
+
+#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;
+} PACKED;
+
+/* CF bit in FLAGS register */
+#define FLAG_CF (1<<0)
+
+static inline void set_cf(struct iregs *regs, int on)
+{
+ if (on)
+ regs->flags |= FLAG_CF;
+ else
+ regs->flags &= ~FLAG_CF;
+}
+
+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
-------------------------------------------------------------------------
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