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

Reply via email to