WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-ia64-devel] [RFC 3/3] hvm-stub for ia64: stubfw

To: Xen-ia64-devel <xen-ia64-devel@xxxxxxxxxxxxxxxxxxx>, Xen-devel <xen-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-ia64-devel] [RFC 3/3] hvm-stub for ia64: stubfw
From: tgingold@xxxxxxx
Date: Thu, 22 Nov 2007 05:01:11 +0100
Delivery-date: Wed, 21 Nov 2007 20:15:11 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-ia64-devel-request@lists.xensource.com?subject=help>
List-id: Discussion of the ia64 port of Xen <xen-ia64-devel.lists.xensource.com>
List-post: <mailto:xen-ia64-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-ia64-devel>, <mailto:xen-ia64-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-ia64-devel>, <mailto:xen-ia64-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-ia64-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Mutt/1.5.9i
diff -r 092232fa1fbd extras/stubfw/.gdb_history
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/.gdb_history        Fri Nov 09 04:05:17 2007 +0100
@@ -0,0 +1,9 @@
+print 128*1024
+print 128*1024
+print 128*1024
+print 128*1024 - 131056
+print 128*1024 - 131056
+print 128*1024 - 131072
+print /x 2095872
+print /x 2095872
+print /x 2097152
diff -r 092232fa1fbd extras/stubfw/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/Makefile    Thu Nov 22 04:14:03 2007 +0100
@@ -0,0 +1,88 @@
+# Common Makefile for hvmstub fw
+#
+
+XEN_ROOT = ../..
+include $(XEN_ROOT)/Config.mk
+
+XEN_INTERFACE_VERSION := 0x00030207
+export XEN_INTERFACE_VERSION
+
+# Set mini-os root path, used in mini-os.mk.
+STUBFW_ROOT=$(PWD)
+export STUBFW_ROOT
+
+# This is used for architecture specific links.
+# This can be overwritten from arch specific rules.
+ARCH_LINKS =
+
+ARCH_CFLAGS=
+ARCH_ASFLAGS=#-Wa,-xauto
+
+# Include common mini-os makerules.
+include stubfw.mk
+
+# Define some default flags for linking.
+LDLIBS := 
+LDFLAGS := -T stubfw.lds
+
+# The common mini-os objects to build.
+OBJS := main.o startup.o  hobs.o events.o \
+ ioemu/serial.o ioemu/mc146818rtc.o ioemu/pci.o ioemu/irq.o \
+ ioemu/piix_pci.o ioemu/ide.o ioemu/cdrom.o ioemu/block.o ioemu/vl.o \
+ ioemu.o console.o xenbus.o xenbus_test.o gnttab.o vbd.o block-vbd.o \
+ event-asm.o \
+ printf.o string.o __umoddi3.o __divdi3.o __udivdi3.o __udivsi3.o __umodsi3.o
+
+.PHONY: default
+default: stubfw
+
+.PHONY: links
+links: $(ARCH_LINKS)
+       [ -e include/xen ] || ln -sf ../../../xen/include/public include/xen
+
+
+stubfw.elf: links $(OBJS)
+       $(LD) $(LDFLAGS) $(OBJS) -Map stubfw.map -o $@
+
+stubfw.bin: stubfw.elf
+       $(OBJCOPY) -v -O binary $< $@
+
+stubfw: stubfw.bin
+       dd if=/dev/zero of=4M.pad bs=1024 count=4096
+       cat stubfw.bin 4M.pad /usr/lib/xen/boot/efi-vms.bin > $@
+
+.PHONY: clean
+
+
+clean:
+       rm -f *.o *~ ioemu/*.o ioemu/*~ 
+       rm -f core stubfw stubfw.bin stubfw.elf 4M.pad
+       rm -f asm-offset.h as-offset.s
+       find . -type l | xargs rm -f
+       rm -f tags TAGS
+
+
+define all_sources
+     ( find . -follow -name SCCS -prune -o -name '*.[chS]' -print )
+endef
+
+.PHONY: cscope
+cscope:
+       $(all_sources) > cscope.files
+       cscope -k -b -q
+
+.PHONY: tags
+tags:
+       $(all_sources) | xargs ctags
+
+.PHONY: TAGS
+TAGS:
+       $(all_sources) | xargs etags
+
+$(OBJS): $(HDRS) Makefile $(EXTRA_DEPS) asm-offset.h
+
+asm-offset.s: asm-offset.c include/callback.h
+       $(CC) -S -o $@ $(CFLAGS) $(CPPFLAGS) $<
+
+asm-offset.h: asm-offset.s
+       sed -ne "/^->/ {s/->/#define /; p}" < $< > $@
diff -r 092232fa1fbd extras/stubfw/__divdi3.S
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/__divdi3.S  Wed Nov 07 00:40:13 2007 +0100
@@ -0,0 +1,141 @@
+.file "__divdi3.s"
+
+// $FreeBSD: src/sys/libkern/ia64/__divdi3.S,v 1.1 2000/10/04 17:53:03 dfr Exp 
$
+//  
+// Copyright (c) 2000, Intel Corporation
+// All rights reserved.
+//
+// Contributed 2/15/2000 by Marius Cornea, John Harrison, Cristina Iordache, 
+// Ted Kubaska, Bob Norin, and Shane Story of the Computational Software Lab, 
+// Intel Corporation.
+//
+// WARRANTY DISCLAIMER
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR ITS 
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Intel Corporation is the author of this code, and requests that all
+// problem reports or change requests be submitted to it directly at
+// http://developer.intel.com/opensource.
+//
+
+.section .text
+.proc __divdi3#
+.align 32
+.global __divdi3#
+.align 32
+
+// 64-bit signed integer divide
+
+__divdi3:
+
+{ .mii
+  alloc r31=ar.pfs,2,0,0,0
+  nop.i 0
+  nop.i 0;;
+} { .mmi
+
+  // 64-BIT SIGNED INTEGER DIVIDE BEGINS HERE
+
+  setf.sig f8=r32
+  setf.sig f9=r33
+  nop.i 0;;
+} { .mfb
+  nop.m 0
+  fcvt.xf f6=f8
+  nop.b 0
+} { .mfb
+  nop.m 0
+  fcvt.xf f7=f9
+  nop.b 0;;
+} { .mfi
+  nop.m 0
+  // Step (1)
+  // y0 = 1 / b in f8
+  frcpa.s1 f8,p6=f6,f7
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (2)
+  // e0 = 1 - b * y0 in f9
+  (p6) fnma.s1 f9=f7,f8,f1
+  nop.i 0
+} { .mfi
+  nop.m 0
+  // Step (3)
+  // q0 = a * y0 in f10
+  (p6) fma.s1 f10=f6,f8,f0
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (4)
+  // e1 = e0 * e0 in f11
+  (p6) fma.s1 f11=f9,f9,f0
+  nop.i 0
+} { .mfi
+  nop.m 0
+  // Step (5)
+  // q1 = q0 + e0 * q0 in f10
+  (p6) fma.s1 f10=f9,f10,f10
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (6)
+  // y1 = y0 + e0 * y0 in f8
+  (p6) fma.s1 f8=f9,f8,f8
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (7)
+  // q2 = q1 + e1 * q1 in f9
+  (p6) fma.s1 f9=f11,f10,f10
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (8)
+  // y2 = y1 + e1 * y1 in f8
+  (p6) fma.s1 f8=f11,f8,f8
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (9)
+  // r2 = a - b * q2 in f10
+  (p6) fnma.s1 f10=f7,f9,f6
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (10)
+  // q3 = q2 + r2 * y2 in f8
+  (p6) fma.s1 f8=f10,f8,f9
+  nop.i 0;;
+} { .mfb
+  nop.m 0
+  // Step (11)
+  // q = trunc (q3)
+  fcvt.fx.trunc.s1 f8=f8
+  nop.b 0;;
+} { .mmi
+  // quotient will be in r8 (if b != 0)
+  getf.sig r8=f8
+  nop.m 0
+  nop.i 0;;
+}
+
+  // 64-BIT SIGNED INTEGER DIVIDE ENDS HERE
+
+{ .mmb
+  nop.m 0
+  nop.m 0
+  br.ret.sptk b0;;
+}
+
+.endp __divdi3
diff -r 092232fa1fbd extras/stubfw/__udivdi3.S
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/__udivdi3.S Wed Nov 07 00:40:13 2007 +0100
@@ -0,0 +1,142 @@
+.file "__udivdi3.s"
+
+// $FreeBSD: src/sys/libkern/ia64/__udivdi3.S,v 1.1 2000/10/04 17:53:03 dfr 
Exp $
+//  
+// Copyright (c) 2000, Intel Corporation
+// All rights reserved.
+//
+// Contributed 2/15/2000 by Marius Cornea, John Harrison, Cristina Iordache, 
+// Ted Kubaska, Bob Norin, and Shane Story of the Computational Software Lab, 
+// Intel Corporation.
+//
+// WARRANTY DISCLAIMER
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR ITS 
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Intel Corporation is the author of this code, and requests that all
+// problem reports or change requests be submitted to it directly at
+// http://developer.intel.com/opensource.
+//
+
+.section .text
+.proc __udivdi3#
+.align 32
+.global __udivdi3#
+.align 32
+
+// 64-bit unsigned integer divide
+
+__udivdi3:
+
+{ .mii
+  alloc r31=ar.pfs,2,0,0,0
+  nop.i 0
+  nop.i 0;;
+}
+
+{ .mmi
+
+  // 64-BIT UNSIGNED INTEGER DIVIDE BEGINS HERE
+
+  setf.sig f8=r32
+  setf.sig f9=r33
+  nop.i 0;;
+} { .mfb
+  nop.m 0
+  fma.s1 f6=f8,f1,f0
+  nop.b 0
+} { .mfb
+  nop.m 0
+  fma.s1 f7=f9,f1,f0
+  nop.b 0;;
+} { .mfi
+  nop.m 0
+  // Step (1)
+  // y0 = 1 / b in f8
+  frcpa.s1 f8,p6=f6,f7
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (2)
+  // e0 = 1 - b * y0 in f9
+  (p6) fnma.s1 f9=f7,f8,f1
+  nop.i 0
+} { .mfi
+  nop.m 0
+  // Step (3)
+  // q0 = a * y0 in f10
+  (p6) fma.s1 f10=f6,f8,f0
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (4)
+  // e1 = e0 * e0 in f11
+  (p6) fma.s1 f11=f9,f9,f0
+  nop.i 0
+} { .mfi
+  nop.m 0
+  // Step (5)
+  // q1 = q0 + e0 * q0 in f10
+  (p6) fma.s1 f10=f9,f10,f10
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (6)
+  // y1 = y0 + e0 * y0 in f8
+  (p6) fma.s1 f8=f9,f8,f8
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (7)
+  // q2 = q1 + e1 * q1 in f9
+  (p6) fma.s1 f9=f11,f10,f10
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (8)
+  // y2 = y1 + e1 * y1 in f8
+  (p6) fma.s1 f8=f11,f8,f8
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (9)
+  // r2 = a - b * q2 in f10
+  (p6) fnma.s1 f10=f7,f9,f6
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (10)
+  // q3 = q2 + r2 * y2 in f8
+  (p6) fma.s1 f8=f10,f8,f9
+  nop.i 0;;
+} { .mfb
+  nop.m 0
+  // (11) q = trunc(q3)
+  fcvt.fxu.trunc.s1 f8=f8
+  nop.b 0;;
+} { .mmi
+  // quotient will be in r8 (if b != 0)
+  getf.sig r8=f8
+  nop.m 0
+  nop.i 0;;
+}
+
+  // 64-BIT UNSIGNED INTEGER DIVIDE ENDS HERE
+
+{ .mmb
+  nop.m 0
+  nop.m 0
+  br.ret.sptk b0;;
+}
+
+.endp __udivdi3
diff -r 092232fa1fbd extras/stubfw/__udivsi3.S
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/__udivsi3.S Thu Nov 15 02:04:22 2007 +0100
@@ -0,0 +1,124 @@
+.file "__udivsi3.s"
+
+// $FreeBSD: src/sys/libkern/ia64/__udivsi3.S,v 1.1.8.1 2005/01/31 23:26:21 
imp Exp $
+
+//-
+// Copyright (c) 2000, Intel Corporation
+// All rights reserved.
+//
+// Contributed 2/15/2000 by Marius Cornea, John Harrison, Cristina Iordache, 
+// Ted Kubaska, Bob Norin, and Shane Story of the Computational Software Lab, 
+// Intel Corporation.
+//
+// WARRANTY DISCLAIMER
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR ITS 
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Intel Corporation is the author of this code, and requests that all
+// problem reports or change requests be submitted to it directly at
+// http://developer.intel.com/opensource.
+//
+
+.section .text
+
+// 32-bit unsigned integer divide
+
+.proc __udivsi3#
+.align 32
+.global __udivsi3#
+.align 32
+
+__udivsi3:
+
+{ .mii
+  alloc r31=ar.pfs,2,0,0,0
+  nop.i 0
+  nop.i 0;;
+} { .mii
+  nop.m 0
+
+  // 32-BIT UNSIGNED INTEGER DIVIDE BEGINS HERE
+
+  // general register used:
+  //    r32 - 32-bit unsigned integer dividend
+  //    r33 - 32-bit unsigned integer divisor
+  //    r8 - 32-bit unsigned integer result
+  //    r2 - scratch register
+  // floating-point registers used: f6, f7, f8, f9
+  // predicate registers used: p6
+
+  zxt4 r32=r32
+  zxt4 r33=r33;;
+} { .mmb
+  setf.sig f6=r32
+  setf.sig f7=r33
+  nop.b 0;;
+} { .mfi
+  nop.m 0
+  fcvt.xf f6=f6
+  nop.i 0
+} { .mfi
+  nop.m 0
+  fcvt.xf f7=f7
+  mov r2 = 0x0ffdd;;
+} { .mfi
+  setf.exp f9 = r2
+  // (1) y0
+  frcpa.s1 f8,p6=f6,f7
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // (2) q0 = a * y0
+  (p6) fma.s1 f6=f6,f8,f0
+  nop.i 0
+} { .mfi
+  nop.m 0
+  // (3) e0 = 1 - b * y0
+  (p6) fnma.s1 f7=f7,f8,f1
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // (4) q1 = q0 + e0 * q0
+  (p6) fma.s1 f6=f7,f6,f6
+  nop.i 0
+} { .mfi
+  nop.m 0
+  // (5) e1 = e0 * e0 + 2^-34
+  (p6) fma.s1 f7=f7,f7,f9
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // (6) q2 = q1 + e1 * q1
+  (p6) fma.s1 f8=f7,f6,f6
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // (7) q = trunc(q2)
+  fcvt.fxu.trunc.s1 f8=f8
+  nop.i 0;;
+} { .mmi
+  // quotient will be in the least significant 32 bits of r8 (if b != 0)
+  getf.sig r8=f8
+  nop.m 0
+  nop.i 0;;
+}
+
+  // 32-BIT UNSIGNED INTEGER DIVIDE ENDS HERE
+
+{ .mmb
+  nop.m 0
+  nop.m 0
+  br.ret.sptk b0;;
+}
+
+.endp __udivsi3
diff -r 092232fa1fbd extras/stubfw/__umoddi3.S
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/__umoddi3.S Wed Nov 07 00:40:13 2007 +0100
@@ -0,0 +1,154 @@
+.file "__umoddi3.s"
+
+// $FreeBSD: src/sys/libkern/ia64/__umoddi3.S,v 1.3 2003/02/11 20:15:11 
schweikh Exp $
+//  
+// Copyright (c) 2000, Intel Corporation
+// All rights reserved.
+//
+// Contributed 2/15/2000 by Marius Cornea, John Harrison, Cristina Iordache, 
+// Ted Kubaska, Bob Norin, and Shane Story of the Computational Software Lab, 
+// Intel Corporation.
+//
+// WARRANTY DISCLAIMER
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR ITS 
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Intel Corporation is the author of this code, and requests that all
+// problem reports or change requests be submitted to it directly at
+// http://developer.intel.com/opensource.
+//
+
+.section .text
+
+  // 64-bit unsigned integer remainder
+
+.proc __umoddi3#
+.align 32
+.global __umoddi3#
+.align 32
+
+__umoddi3:
+
+{ .mii
+  alloc r31=ar.pfs,3,0,0,0
+  nop.i 0
+  nop.i 0
+} { .mmb
+
+  // 64-BIT UNSIGNED INTEGER REMAINDER BEGINS HERE
+
+  // general register used:
+  //    r32 - 64-bit unsigned integer dividend, called a below
+  //    r33 - 64-bit unsigned integer divisor, called b below
+  //    r8 - 64-bit unsigned integer result
+  // floating-point registers used: f6, f7, f8, f9, f10, f11, f12
+  // predicate registers used: p6
+
+  setf.sig f12=r32  // holds a in integer form
+  setf.sig f7=r33
+  nop.b 0;;
+} { .mfi
+  // get 2s complement of b
+  sub r33=r0,r33
+  fcvt.xuf.s1 f6=f12
+  nop.i 0
+} { .mfi
+  nop.m 0
+  fcvt.xuf.s1 f7=f7
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (1)
+  // y0 = 1 / b in f8
+  frcpa.s1 f8,p6=f6,f7
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (2)
+  // q0 = a * y0 in f10
+  (p6) fma.s1 f10=f6,f8,f0
+  nop.i 0
+} { .mfi
+  nop.m 0
+  // Step (3)
+  // e0 = 1 - b * y0 in f9
+  (p6) fnma.s1 f9=f7,f8,f1
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (4)
+  // q1 = q0 + e0 * q0 in f10
+  (p6) fma.s1 f10=f9,f10,f10
+  nop.i 0
+} { .mfi
+  nop.m 0
+  // Step (5)
+  // e1 = e0 * e0 in f11
+  (p6) fma.s1 f11=f9,f9,f0
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (6)
+  // y1 = y0 + e0 * y0 in f8
+  (p6) fma.s1 f8=f9,f8,f8
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (7)
+  // q2 = q1 + e1 * q1 in f9
+  (p6) fma.s1 f9=f11,f10,f10
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (8)
+  // y2 = y1 + e1 * y1 in f8
+  (p6) fma.s1 f8=f11,f8,f8
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // Step (9)
+  // r2 = a - b * q2 in f10
+  (p6) fnma.s1 f10=f7,f9,f6
+  nop.i 0;;
+} { .mfi
+  // f7=-b
+  setf.sig f7=r33
+  // Step (10)
+  // q3 = q2 + r2 * y2 in f8
+  (p6) fma.s1 f8=f10,f8,f9
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // (11) q = trunc(q3)
+  fcvt.fxu.trunc.s1 f8=f8
+  nop.i 0;;
+}  { .mfi
+  nop.m 0
+  // (12) r = a + (-b) * q
+  xma.l f8=f8,f7,f12
+  nop.i 0;;
+}  { .mib
+  getf.sig r8=f8
+  nop.i 0
+  nop.b 0
+}
+
+  // 64-BIT UNSIGNED INTEGER REMAINDER ENDS HERE
+
+{ .mib
+  nop.m 0
+  nop.i 0
+  br.ret.sptk b0;;
+}
+
+.endp __umoddi3
diff -r 092232fa1fbd extras/stubfw/__umodsi3.S
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/__umodsi3.S Thu Nov 15 02:05:23 2007 +0100
@@ -0,0 +1,131 @@
+.file "__umodsi3.s"
+
+// $FreeBSD: src/sys/libkern/ia64/__umodsi3.S,v 1.1.8.1 2005/01/31 23:26:21 
imp Exp $
+
+//-
+// Copyright (c) 2000, Intel Corporation
+// All rights reserved.
+//
+// Contributed 2/15/2000 by Marius Cornea, John Harrison, Cristina Iordache, 
+// Ted Kubaska, Bob Norin, and Shane Story of the Computational Software Lab, 
+// Intel Corporation.
+//
+// WARRANTY DISCLAIMER
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR ITS 
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Intel Corporation is the author of this code, and requests that all
+// problem reports or change requests be submitted to it directly at
+// http://developer.intel.com/opensource.
+//
+
+.section .text
+
+// 32-bit unsigned integer remainder
+
+.proc __umodsi3#
+.align 32
+.global __umodsi3#
+.align 32
+
+__umodsi3:
+
+{ .mii
+  alloc r31=ar.pfs,2,0,0,0
+  nop.i 0
+  nop.i 0;;
+} { .mii
+  nop.m 0
+
+  // 32-BIT UNSIGNED INTEGER REMAINDER BEGINS HERE
+
+  // general register used:
+  //    r32 - 32-bit unsigned integer dividend
+  //    r33 - 32-bit unsigned integer divisor
+  //    r8 - 32-bit unsigned integer result
+  //    r2 - scratch register
+  // floating-point registers used: f6, f7, f8, f9, f10, f11
+  // predicate registers used: p6
+
+  zxt4 r32=r32
+  zxt4 r33=r33;;
+} { .mmb
+  setf.sig f11=r32
+  setf.sig f7=r33
+  nop.b 0;;
+} { .mfi
+  nop.m 0
+  fcvt.xf f6=f11
+  nop.i 0
+} { .mfi
+  // get 2's complement of b
+  sub r33=r0,r33
+  fcvt.xf f7=f7
+  mov r2 = 0x0ffdd;;
+} { .mfi
+  setf.exp f9 = r2
+  // (1) y0
+  frcpa.s1 f8,p6=f6,f7
+  nop.i 0;;
+}  { .mfi
+  nop.m 0
+  // (2) q0 = a * y0
+  (p6) fma.s1 f10=f6,f8,f0
+  nop.i 0
+} { .mfi
+  nop.m 0
+  // (3) e0 = 1 - b * y0
+  (p6) fnma.s1 f8=f7,f8,f1
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // (4) q1 = q0 + e0 * q0
+  (p6) fma.s1 f10=f8,f10,f10
+  nop.i 0
+} { .mfi
+  // get 2's complement of b
+  setf.sig f7=r33
+  // (5) e1 = e0 * e0 + 2^-34
+  (p6) fma.s1 f8=f8,f8,f9
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // (6) q2 = q1 + e1 * q1
+  (p6) fma.s1 f8=f8,f10,f10
+  nop.i 0;;
+} { .mfi
+  nop.m 0
+  // (7) q = trunc(q2)
+  fcvt.fxu.trunc.s1 f8=f8
+  nop.i 0;;
+}  { .mfi
+  nop.m 0
+  // (8) r = a + (-b) * q
+  xma.l f8=f8,f7,f11
+  nop.i 0;;
+}  { .mmi
+  // remainder will be in the least significant 32 bits of r8 (if b != 0)
+  getf.sig r8=f8
+  nop.m 0
+  nop.i 0;;
+}
+
+  // 32-BIT UNSIGNED INTEGER REMAINDER ENDS HERE
+
+{ .mmb
+  nop.m 0
+  nop.m 0
+  br.ret.sptk b0;;
+}
+
+.endp __umodsi3
diff -r 092232fa1fbd extras/stubfw/asm-offset.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/asm-offset.c        Thu Nov 22 04:07:56 2007 +0100
@@ -0,0 +1,54 @@
+#include "callback.h"
+
+#define DEFINE(sym, val)                                       \
+  asm volatile("\n->" sym " %0 /* " #val " */": : "i" (val))
+
+#define CB_OFF(F,N) DEFINE("IA64_CB_"#N, offsetof(struct ia64_cb_regs, F))
+
+int
+main(int argc, char ** argv)
+{
+  CB_OFF (unat, UNAT);
+  CB_OFF (r1, R1);
+  CB_OFF (r2, R2);
+  CB_OFF (r3, R3);
+  CB_OFF (r4, R4);
+  CB_OFF (r5, R5);
+  CB_OFF (r8, R8);
+  CB_OFF (r9, R9);
+  CB_OFF (r10, R10);
+  CB_OFF (r11, R11);
+  CB_OFF (r12, R12);
+  CB_OFF (r13, R13);
+  CB_OFF (r14, R14);
+  CB_OFF (r15, R15);
+  CB_OFF (pr, PR);
+  CB_OFF (b0, B0);
+  CB_OFF (b6, B6);
+  CB_OFF (b7, B7);
+  CB_OFF (fpsr, FPSR);
+  CB_OFF (f6, F6);
+  CB_OFF (f7, F7);
+  CB_OFF (f8, F8);
+  CB_OFF (f9, F9);
+  CB_OFF (f10, F10);
+  CB_OFF (f11, F11);
+  CB_OFF (rsc, RSC);
+  CB_OFF (pfs, PFS);
+  CB_OFF (ccv, CCV);
+  CB_OFF (csd, CSD);
+  CB_OFF (ssd, SSD);
+  CB_OFF (nats, NATS);
+  CB_OFF (ip, IP);
+  CB_OFF (psr, PSR);
+  CB_OFF (cfm, CFM);
+  CB_OFF (rsv, RSV);
+  CB_OFF (bspstore, BSPSTORE);
+  CB_OFF (rnat, RNAT);
+  CB_OFF (ndirty, NDIRTY);
+  CB_OFF (rbs, RBS);
+
+  return 0;
+}
+
+  
diff -r 092232fa1fbd extras/stubfw/asm-offset.i
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/asm-offset.i        Thu Nov 22 04:06:59 2007 +0100
@@ -0,0 +1,995 @@
+#define atomic_subtract_32 atomic_subtract_acq_32
+#define __HYPERVISOR_dom0_op __HYPERVISOR_platform_op
+#define _PTRDIFF_T_ 
+#define GNTCOPY_source_gref (1<<_GNTCOPY_source_gref)
+#define XENMEM_memory_map 9
+#define ASSIGN_readonly (1UL << _ASSIGN_readonly)
+#define ENOANO 55
+#define GTF_writing (1U<<_GTF_writing)
+#define __DBL_MIN_EXP__ (-1021)
+#define local_irq_restore(x) __restore_flags(x)
+#define EMULTIHOP 72
+#define BUG() { printk("mini-os BUG at %s:%d!\n", __FILE__, __LINE__); exit(); 
}
+#define __HYPERVISOR_callback_op 30
+#define GNTST_no_device_space (-7)
+#define FDESC_FUNC(fn) (((struct ia64_fdesc *) fn)->func)
+#define xen_vga_console_info_t dom0_vga_console_info_t
+#define IA64_FPSR_TRAP_UD UL_CONST(0x0000000000000010)
+#define __INT_WCHAR_T_H 
+#define INVALID_MFN (~0UL)
+#define atomic_add_int atomic_add_32
+#define XENFEAT_NR_SUBMAPS 1
+#define MMUEXT_INVLPG_LOCAL 7
+#define atomic_subtract_64 atomic_subtract_acq_64
+#define _ERRNO_BASE_H 
+#define __ia64__ 1
+#define ENOTSOCK 88
+#define __FLT_MIN__ 1.17549435e-38F
+#define __XEN_PUBLIC_GRANT_TABLE_H__ 
+#define XEN_IA64_DEBUG_ON_EXCEPT (1 << 4)
+#define VIRQ_TIMER 0
+#define _T_PTRDIFF_ 
+#define ENOMEM 12
+#define atomic_set_short atomic_set_16
+#define EUSERS 87
+#define HYPERPRIVOP_SSM_I (HYPERPRIVOP_START + 0x6)
+#define _T_WCHAR_ 
+#define EUNATCH 49
+#define XENVER_get_features 6
+#define atomic_cmpset_32 atomic_cmpset_acq_32
+#define IA64_PSR_CPL 0x0000000300000000
+#define XENMEM_decrease_reservation 1
+#define ESTALE 116
+#define __HYPERVISOR_set_timer_op 15
+#define IA64_VEC_DEBUG 29
+#define atomic_clear_64 atomic_clear_acq_64
+#define DEFINE_XEN_GUEST_HANDLE(name) __DEFINE_XEN_GUEST_HANDLE(name, name)
+#define XENVER_extraversion 1
+#define HYPERPRIVOP_SET_TPR (HYPERPRIVOP_START + 0x9)
+#define EBADFD 77
+#define IA64_PSR_AC 0x0000000000000008
+#define atomic_add_acq_int atomic_add_acq_32
+#define IA64_FPSR_TRAP_ZD UL_CONST(0x0000000000000004)
+#define HYPERPRIVOP_SET_ITM (HYPERPRIVOP_START + 0xb)
+#define __XEN_LATEST_INTERFACE_VERSION__ 0x00030207
+#define MMUEXT_PIN_L4_TABLE 3
+#define XEN_IA64_OPTF_IDENT_MAP_REG7 (1UL << XEN_IA64_OPTF_IDENT_MAP_REG7_BIT)
+#define XENMEM_machine_memory_map 10
+#define uint64_aligned_t uint64_t
+#define atomic_set_acq_char atomic_set_acq_8
+#define __cli() do { vcpu_info_t *_vcpu; _vcpu = 
&HYPERVISOR_shared_info->vcpu_info[smp_processor_id()]; 
_vcpu->evtchn_upcall_mask = SWAP(1); barrier(); } while (0)
+#define __CHAR_BIT__ 8
+#define IA64_PSR_BE 0x0000000000000002
+#define IA64_PSR_BN 0x0000100000000000
+#define IA64_VEC_INST_ACCESS 9
+#define EAFNOSUPPORT 97
+#define HYPERPRIVOP_START 0x1
+#define _hypercall0(type,name) ({ long __res; __res = __hypercall(0, 0, 0, 0, 
0, __HYPERVISOR_ ##name); (type)__res; })
+#define _hypercall1(type,name,a1) ({ long __res; __res = __hypercall((unsigned 
long)a1, 0, 0, 0, 0, __HYPERVISOR_ ##name); (type)__res; })
+#define _hypercall2(type,name,a1,a2) ({ long __res; __res = 
__hypercall((unsigned long)a1, (unsigned long)a2, 0, 0, 0, __HYPERVISOR_ 
##name); (type)__res; })
+#define _hypercall3(type,name,a1,a2,a3) ({ long __res; __res = 
__hypercall((unsigned long)a1, (unsigned long)a2, (unsigned long)a3, 0, 0, 
__HYPERVISOR_ ##name); (type)__res; })
+#define _hypercall4(type,name,a1,a2,a3,a4) ({ long __res; __res = 
__hypercall((unsigned long)a1, (unsigned long)a2, (unsigned long)a3, (unsigned 
long)a4, 0, __HYPERVISOR_ ##name); (type)__res; })
+#define __SIZE_T__ 
+#define __HYPERVISOR_domctl 36
+#define EACCES 13
+#define GNTST_bad_handle (-4)
+#define EVTCHNSTAT_pirq 3
+#define HYPERPRIVOP_GET_PMD (HYPERPRIVOP_START + 0x14)
+#define IA64_PSR_DB 0x0000000001000000
+#define IA64_PSR_DD 0x0000008000000000
+#define EDESTADDRREQ 89
+#define IA64_PSR_DI 0x0000000000400000
+#define IA64_DCR_BE 1
+#define IA64_PSR_DT 0x0000000000020000
+#define CONSOLEIO_write 0
+#define HYPERPRIVOP_FC (HYPERPRIVOP_START + 0x12)
+#define IA64_PSR_CPL_USER 0x0000000300000000
+#define _SYS_SIZE_T_H 
+#define IA64_PSR_ED 0x0000080000000000
+#define IA64_DCR_MBZ0 4
+#define IA64_DCR_MBZ1 2
+#define XMAPPEDREGS_OFS XSI_SIZE
+#define GNTTABOP_unmap_grant_ref 1
+#define EVTCHNOP_bind_interdomain 0
+#define HVMSTUB_HYPERCALL_SET_CALLBACK 0x801
+#define VMASST_CMD_disable 1
+#define __XEN_PUBLIC_HVM_HVM_OP_H__ 
+#define IA64_ISR_EI_0 0x0000000000000000
+#define IA64_ISR_EI_1 0x0000020000000000
+#define IA64_ISR_EI_2 0x0000040000000000
+#define IA64_DCR_DA 13
+#define IA64_DCR_DD 14
+#define ELOOP 40
+#define IA64_DCR_DK 10
+#define IA64_DCR_DM 8
+#define EILSEQ 84
+#define va_start(v,l) __builtin_va_start(v,l)
+#define IA64_DCR_DP 9
+#define IA64_DCR_DR 12
+#define MMUEXT_PIN_L2_TABLE 1
+#define _HYPERVISOR_H_ 
+#define IA64_DCR_DX 11
+#define _IA64_FPU_H_ 
+#define ESPIPE 29
+#define XSI_SIZE (1 << XSI_SHIFT)
+#define PIB_START 0xfee00000UL
+#define IA64_VEC_BREAK 11
+#define EMLINK 31
+#define set_xen_guest_handle(hnd,val) do { (hnd).p = val; } while (0)
+#define DOMID_XEN (0x7FF2U)
+#define XENVER_platform_parameters 5
+#define atomic_subtract_acq_char atomic_subtract_acq_8
+#define __WCHAR_MAX__ 2147483647
+#define PRINT_BV(_fmt,_params...) if (bootverbose) printk(_fmt , ## _params)
+#define atomic_set_char atomic_set_8
+#define XEN_IA64_DEBUG_ON_TC (1 << 16)
+#define __XEN_PUBLIC_FEATURES_H__ 
+#define XEN_IA64_DEBUG_ON_TR (1 << 15)
+#define IA64_SF_DEFAULT (IA64_SF_PC_3 | IA64_SF_RC_NEAREST)
+#define EL2HLT 51
+#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+#define atomic_set_int atomic_set_32
+#define IA64_PSR_IA 0x0000200000000000
+#define IA64_PSR_IC (1<<IA64_PSR_IC_BIT)
+#define IA64_PSR_ID 0x0000002000000000
+#define __save_flags(x) do { vcpu_info_t *_vcpu; _vcpu = 
&HYPERVISOR_shared_info->vcpu_info[smp_processor_id()]; (x) = 
SWAP(_vcpu->evtchn_upcall_mask); } while (0)
+#define GNTTABOP_copy 5
+#define __va_copy(d,s) __builtin_va_copy(d,s)
+#define IA64_PSR_IS 0x0000000400000000
+#define IA64_PSR_IT 0x0000001000000000
+#define MMU_NORMAL_PT_UPDATE 0
+#define safe_halt() ((void)0)
+#define ENOKEY 126
+#define LEGACY_IO_SIZE (64*MEM_M)
+#define __HYPERVISOR_xsm_op 27
+#define HYPERPRIVOP_GET_PSR (HYPERPRIVOP_START + 0x18)
+#define __FLT_EVAL_METHOD__ 0
+#define HVMOP_get_param 1
+#define XENFEAT_writable_descriptor_tables 1
+#define __unix__ 1
+#define EINVAL 22
+#define _ANSI_STDARG_H_ 
+#define __HYPERVISOR_mmuext_op 26
+#define UVMF_INVLPG (2UL<<0)
+#define UVMF_TLB_FLUSH (1UL<<0)
+#define IA64_RR_IDX_POS 61
+#define unix 1
+#define IA64_PSR_LP 0x0000000002000000
+#define __HYPERVISOR_vcpu_op 24
+#define VGA_IO_SIZE 0x20000
+#define GTF_transfer_committed (1U<<_GTF_transfer_committed)
+#define __XEN_PUBLIC_SCHED_H__ 
+#define ESHUTDOWN 108
+#define PTE_PL_KERN 0
+#define IA64_PSR_MC 0x0000000800000000
+#define EKEYREJECTED 129
+#define _BSD_SIZE_T_ 
+#define IA64_PSR_DFH 0x0000000000080000
+#define __SIZE_TYPE__ long unsigned int
+#define _SIZE_T_DECLARED 
+#define irqs_disabled() 
SWAP(HYPERVISOR_shared_info->vcpu_info[smp_processor_id()].evtchn_upcall_mask)
+#define IA64_VEC_DATA_ACCESS_RIGHTS 23
+#define IA64_DOM0VP_unexpose_foreign_p2m 13
+#define XENVER_pagesize 7
+#define EVTCHNOP_send 4
+#define IA64_DCR_LC 2
+#define XEN_IA64_DEBUG_OP_SET_FLAGS 1
+#define IA64_PSR_DFL 0x0000000000040000
+#define atomic_set_16 atomic_set_acq_16
+#define EOWNERDEAD 130
+#define SCHEDOP_block 1
+#define XENMEM_machphys_mapping 12
+#define SHUTDOWN_crash 3
+#define _GNTCOPY_dest_gref (1)
+#define __ia64 1
+#define EVTCHNSTAT_closed 0
+#define IA64_RR_MBZ1 32
+#define UL_TYPE(x) ((uint64_t)x)
+#define __ELF__ 1
+#define ENOMEDIUM 123
+#define __DBL_MIN_10_EXP__ (-307)
+#define IA64_PSR_PK 0x0000000000008000
+#define IA64_PSR_PP 0x0000000000200000
+#define PTE_OFF_AR 9
+#define ENOTTY 25
+#define __FINITE_MATH_ONLY__ 0
+#define atomic_set_32 atomic_set_acq_32
+#define XEN_IA64_DEBUG_ON_SAL (1 << 8)
+#define atomic_clear_rel_short atomic_clear_rel_16
+#define wmb() mb()
+#define __HYPERVISOR_set_callbacks 4
+#define MAX_VIRT_CPUS 64
+#define atomic_add_rel_short atomic_add_rel_16
+#define EBADE 52
+#define EBADF 9
+#define ELIBSCN 81
+#define CONSOLEIO_read 1
+#define XEN_IA64_DEBUG_OP_TRANSLATE 4
+#define EBADR 53
+#define GTF_PAT (1U<<_GTF_PAT)
+#define IA64_PSR_RI 0x0000060000000000
+#define __STDDEF_H__ 
+#define MMUEXT_NEW_USER_BASEPTR 15
+#define IA64_VEC_VHPT 0
+#define IA64_PSR_RT 0x0000000008000000
+#define IA64_DCR_PP 0
+#define SCHEDOP_remote_shutdown 4
+#define atomic_set_rel_short atomic_set_rel_16
+#define EADV 68
+#define ERANGE 34
+#define __GNUC_PATCHLEVEL__ 5
+#define ECANCELED 125
+#define __FLT_RADIX__ 2
+#define IA64_PSR_SI 0x0000000000800000
+#define IA64_PSR_SP 0x0000000000100000
+#define IA64_PSR_SS 0x0000010000000000
+#define __LDBL_EPSILON__ 1.08420217248550443401e-19L
+#define IA64_RSC_LOADRS_LEN 14
+#define __HYPERVISOR_get_debugreg 9
+#define MMUEXT_TLB_FLUSH_LOCAL 6
+#define atomic_add_char atomic_add_8
+#define GTF_PCD (1U<<_GTF_PCD)
+#define atomic_set_64 atomic_set_acq_64
+#define MMUEXT_PIN_L1_TABLE 0
+#define __HYPERVISOR_nmi_op 28
+#define __size_t 
+#define XEN_IA64_DEBUG_ON_KERN_DEBUG (1 << 1)
+#define _WCHAR_T_DEFINED 
+#define ETXTBSY 26
+#define IA64_PSR_UP 0x0000000000000004
+#define ENAVAIL 119
+#define atomic_add_8 atomic_add_acq_8
+#define _GNTMAP_device_map (0)
+#define _ERRNO_H 
+#define CB_OFF(F,N) DEFINE("IA64_CB_"#N, offsetof(struct ia64_cb_regs, F))
+#define IA64_RR_PS 2
+#define EVTCHNSTAT_ipi 5
+#define EVTCHNOP_bind_virq 1
+#define __HYPERVISOR_ia64_dom0vp_op __HYPERVISOR_arch_0
+#define IA64_VEC_IA32_INTERCEPT 46
+#define HYPERPRIVOP_RSM_DT (HYPERPRIVOP_START + 0x1)
+#define __SHRT_MAX__ 32767
+#define SIF_INITDOMAIN (1<<1)
+#define PTE_AR_RX_RWX 5
+#define HYPERPRIVOP_COVER (HYPERPRIVOP_START + 0x3)
+#define __LDBL_MAX__ 1.18973149535723176502e+4932L
+#define _GTF_transfer_completed (3)
+#define GNTST_permission_denied (-8)
+#define MMUEXT_INVLPG_MULTI 9
+#define EVTCHNOP_status 5
+#define atomic_subtract_long atomic_subtract_64
+#define IA64_SF_D UL_CONST(0x0100)
+#define IA64_PSR_CPL_1 0x0000000100000000
+#define IA64_PSR_CPL_2 0x0000000200000000
+#define atomic_subtract_rel_long atomic_subtract_rel_64
+#define XEN_CHANGESET_INFO_LEN (sizeof(xen_changeset_info_t))
+#define SCHEDOP_yield 0
+#define HVMOP_set_param 0
+#define __HYPERVISOR_event_channel_op_compat 16
+#define MMU_MACHPHYS_UPDATE 1
+#define IA64_ISR_R 0x0000000400000000
+#define XENMEM_translate_gpfn_list 8
+#define XENVER_version 0
+#define HYPERPRIVOP_GET_RR (HYPERPRIVOP_START + 0xf)
+#define IA64_DOM0VP_add_io_space 11
+#define barrier() __asm__ __volatile__("": : :"memory")
+#define EBUSY 16
+#define EINPROGRESS 115
+#define __HYPERVISOR_platform_op 7
+#define _LIB_H_ 
+#define IA64_RR_VE 0
+#define __OS_H__ 
+#define GNTST_general_error (-1)
+#define _SIZE_T_ 
+#define IA64_SF_FTZ UL_CONST(0x0001)
+#define mk_unsigned_long(x) __mk_unsigned_long(x)
+#define __linux 1
+#define MOS_IA64_PSR_BE 0
+#define _WCHAR_T_H 
+#define EPROTO 71
+#define ENODEV 19
+#define __HYPERVISOR_xen_version 17
+#define __HYPERVISOR_set_segment_base 25
+#define __unix 1
+#define ASSERT(x) do { if (!(x)) { printk("ASSERTION FAILED: %s at %s:%d.\n", 
#x , __FILE__, __LINE__); BUG(); } } while(0)
+#define PTE_OFF_PL 7
+#define atomic_cmpset_rel_long atomic_cmpset_rel_64
+#define HYPERPRIVOP_GET_TPR (HYPERPRIVOP_START + 0x8)
+#define GFW_SIZE (16*MEM_M)
+#define INT_MAX ((int)(~0U>>1))
+#define __HYPERVISOR_console_io 18
+#define likely(x) __builtin_expect(!!(x), 1)
+#define EMSGSIZE 90
+#define IA64_SF_RC_POSINF UL_CONST(0x0020)
+#define MOS_IA64_DCR_BE (0 << IA64_DCR_BE)
+#define PAGE_SHIFT 14
+#define __SIZE_T 
+#define EREMCHG 78
+#define XEN_IA64_DEBUG_OP_GET_FLAGS 2
+#define EKEYEXPIRED 127
+#define __HYPERCALL_H__ 
+#define __LDBL_MAX_EXP__ 16384
+#define EROFS 30
+#define ENOTEMPTY 39
+#define GNTTABOP_transfer 4
+#define ENOTBLK 15
+#define IA64_VEC_NAT_CONSUMPTION 26
+#define IA64_RSC_LOADRS 16
+#define UVMF_NONE (0UL<<0)
+#define HYPERPRIVOP_GET_IVR (HYPERPRIVOP_START + 0x7)
+#define __HYPERVISOR_opt_feature 0x700UL
+#define EPROTOTYPE 91
+#define ERESTART 85
+#define IA64_AR(name) static __inline uint64_t ia64_get_ ##name(void) { 
uint64_t result; __asm __volatile(";;mov %0=ar." #name ";;" : "=r" (result)); 
return result; } static __inline void ia64_set_ ##name(uint64_t v) { __asm 
__volatile("mov ar." #name "=%0" :: "r" (v)); }
+#define EVTCHNOP_bind_ipi 7
+#define _hypercall5(type,name,a1,a2,a3,a4,a5) ({ long __res; __res = 
__hypercall((unsigned long)a1, (unsigned long)a2, (unsigned long)a3, (unsigned 
long)a4, (unsigned long)a5, __HYPERVISOR_ ##name); (type)__res; })
+#define EISNAM 120
+#define local_irq_enable() __sti()
+#define __LONG_MAX__ 9223372036854775807L
+#define __linux__ 1
+#define __HYPERVISOR_update_va_mapping_otherdomain 22
+#define ELIBACC 79
+#define va_copy(d,s) __builtin_va_copy(d,s)
+#define _GNTMAP_readonly (2)
+#define GTF_reading (1U<<_GTF_reading)
+#define atomic_set_rel_int atomic_set_rel_32
+#define ENOMSG 42
+#define IA64_RSC_BE 4
+#define _SIZE_T_DEFINED_ 
+#define IA64_CR(name) static __inline uint64_t ia64_get_ ##name(void) { 
uint64_t result; __asm __volatile("mov %0=cr." #name : "=r" (result)); return 
result; } static __inline void ia64_set_ ##name(uint64_t v) { __asm 
__volatile("mov cr." #name "=%0" :: "r" (v)); }
+#define _BSD_PTRDIFF_T_ 
+#define __HYPERVISOR_physdev_op __HYPERVISOR_physdev_op_compat
+#define __SCHAR_MAX__ 127
+#define EALREADY 114
+#define IA64_DOM0VP_perfmon 8
+#define _GTF_writing (4)
+#define MMIO_START (3 * MEM_G)
+#define XEN_IA64_DEBUG_ON_EXTINT (1 << 3)
+#define NULL ((void *)0)
+#define IA64_PSR_UMASK (IA64_PSR_BE | IA64_PSR_UP | IA64_PSR_AC | IA64_PSR_MFL 
| IA64_PSR_MFH)
+#define PTE_AR_R 0
+#define VIRQ_ITC VIRQ_ARCH_0
+#define __HYPERVISOR_IF_IA64_H__ 
+#define GNTST_bad_page (-9)
+#define E2BIG 7
+#define __DBL_DIG__ 15
+#define HYPERVISOR_console_io xencomm_arch_console_io
+#define PTE_PL_SHIFT 7
+#define atomic_clear_rel_char atomic_clear_rel_8
+#define _VA_LIST_DEFINED 
+#define XEN_IA64_DEBUG_ON_BAD_MPA (1 << 12)
+#define HYPERPRIVOP_THASH (HYPERPRIVOP_START + 0xc)
+#define IA64_DOM0VP_add_physmap_with_gmfn 9
+#define EVTCHNOP_alloc_unbound 6
+#define STARTUP_PSR (IA64_PSR_IT | IA64_PSR_PK | IA64_PSR_DT | IA64_PSR_RT | 
MOS_IA64_PSR_BE | IA64_PSR_BN | IA64_PSR_CPL_KERN | IA64_PSR_AC)
+#define EVTCHNSTAT_virq 4
+#define IA64_PKR_RD 2
+#define _GTF_readonly (2)
+#define PTE_A 1
+#define EDEADLK 35
+#define IA64_ITIR_MBZ0 0
+#define IA64_ITIR_MBZ1 32
+#define IA64_ITIR_MBZ2 63
+#define HYPERVISOR_sched_op xencomm_arch_sched_op
+#define EL3RST 47
+#define IA64_GR(name) static __inline uint64_t ia64_get_ ##name(void) { 
uint64_t result; __asm __volatile("mov %0=" #name : "=r" (result)); return 
result; } static __inline void ia64_set_ ##name(uint64_t v) { __asm 
__volatile("mov " #name "=%0" :: "r" (v)); }
+#define local_save_flags(x) __save_flags(x)
+#define HVMOP_set_pci_intx_level 2
+#define GTF_PWT (1U<<_GTF_PWT)
+#define atomic_clear_16 atomic_clear_acq_16
+#define GFW_START (4*MEM_G -16*MEM_M)
+#define IA64_PSR_CPL_KERN 0x0000000000000000
+#define __XEN_PUBLIC_XEN_COMPAT_H__ 
+#define IA64_DOM0VP_machtophys 3
+#define SCHEDOP_shutdown 2
+#define ASSIGN_tlb_track (1UL << _ASSIGN_tlb_track)
+#define VGA_IO_START 0xA0000UL
+#define ENOTDIR 20
+#define EDOM 33
+#define HYPERVISOR_event_channel_op xencomm_arch_event_channel_op
+#define __HYPERVISOR_set_trap_table 0
+#define __HYPERVISOR_fpu_taskswitch 5
+#define local_irq_save(x) __save_and_cli(x)
+#define ETIMEDOUT 110
+#define IA64_VEC_PAGE_NOT_PRESENT 20
+#define __XEN_PUBLIC_XEN_H__ 
+#define ECONNRESET 104
+#define HVMOP_set_pci_link_route 4
+#define __USER_LABEL_PREFIX__ 
+#define atomic_add_16 atomic_add_acq_16
+#define IA64_VEC_EXT_INTR 12
+#define HYPERPRIVOP_EOI (HYPERPRIVOP_START + 0xa)
+#define HYPERPRIVOP_GET_CPUID (HYPERPRIVOP_START + 0x13)
+#define _ASSIGN_pgc_allocated 3
+#define IA64_PSR_MFH (1 << IA64_PSR_MFH_BIT)
+#define ENODATA 61
+#define _ASSIGN_readonly 0
+#define linux 1
+#define IA64_PKR_WD 1
+#define __DEFINE_XEN_GUEST_HANDLE(name,type) typedef type * __guest_handle_ ## 
name
+#define IA64_DOM0VP_expose_foreign_p2m 12
+#define ENXIO 6
+#define atomic_cmpset_long atomic_cmpset_64
+#define IA64_RSC_PL 2
+#define IA64_VEC_KEY_PERMISSION 21
+#define IA64_PKR_XD 3
+#define atomic_add_32 atomic_add_acq_32
+#define EOVERFLOW 75
+#define EVTCHNSTAT_interdomain 2
+#define IA64_RSC_MBZ0_V 0x3ff
+#define __STDC_HOSTED__ 1
+#define EBADRQC 56
+#define IO_PAGE_START (LEGACY_IO_START + LEGACY_IO_SIZE)
+#define IA64_PSR_RI_SHIFT 41
+#define XENMEM_current_reservation 3
+#define __HYPERVISOR_multicall 13
+#define IA64_PSR_I_BIT 14
+#define XEN_IA64_OPTF_ON 0x1
+#define MMUEXT_TLB_FLUSH_MULTI 8
+#define HYPERPRIVOP_SSM_DT (HYPERPRIVOP_START + 0x2)
+#define ENOSTR 60
+#define IA64_DOM0VP_fpswa_revision 10
+#define __aligned(x) __attribute__((__aligned__(x)))
+#define XENMEM_maximum_reservation 4
+#define IA64_PKR_KEY_LEN 24
+#define IA64_PSR_MFL 0x0000000000000010
+#define atomic_add_64 atomic_add_acq_64
+#define __LDBL_MANT_DIG__ 64
+#define NR_VIRQS 24
+#define GTF_type_mask (3U<<0)
+#define _BSD_SIZE_T_DEFINED_ 
+#define __itanium__ 1
+#define IA64_PSR_MFH_BIT 5
+#define __HYPERVISOR_mmu_update 1
+#define ENAMETOOLONG 36
+#define FDESC_GP(fn) (((struct ia64_fdesc *) fn)->gp)
+#define EINTR 4
+#define PTE_OFF_A 5
+#define PTE_OFF_D 6
+#define __HYPERVISOR_update_va_mapping 14
+#define HYPERPRIVOP_RFI (HYPERPRIVOP_START + 0x0)
+#define PTE_OFF_P 0
+#define IA64_VEC_ITLB 1
+#define __FLT_EPSILON__ 1.19209290e-7F
+#define IA64_DOM0VP_zap_physmap 5
+#define _LONGLONG 1
+#define ENOLINK 67
+#define VIRQ_CONSOLE 2
+#define XEN_IA64_DEBUG_ON_EVENT (1 << 5)
+#define GNTMAP_host_map (1<<_GNTMAP_host_map)
+#define XENMAPSPACE_grant_table 1
+#define __GNUC_VA_LIST 
+#define atomic_subtract_8 atomic_subtract_acq_8
+#define XEN_GUEST_HANDLE_00030205(type) type *
+#define IA64_ITIR_PPN_LEN 15
+#define HVMOP_flush_tlbs 5
+#define IA64_PSR_I (1<<IA64_PSR_I_BIT)
+#define PTE_PS_16K 14
+#define PTE_AR_RWX_RW 6
+#define __HYPERVISOR_arch_0 48
+#define __HYPERVISOR_arch_1 49
+#define __HYPERVISOR_arch_2 50
+#define __HYPERVISOR_arch_3 51
+#define __HYPERVISOR_arch_4 52
+#define __HYPERVISOR_arch_5 53
+#define __HYPERVISOR_arch_6 54
+#define __HYPERVISOR_arch_7 55
+#define PTE_PS_16M 24
+#define VMASST_TYPE_4gb_segments_notify 1
+#define IA64_VEC_DISABLED_FP 25
+#define atomic_set_8 atomic_set_acq_8
+#define ESOCKTNOSUPPORT 94
+#define atomic_add_acq_long atomic_add_acq_64
+#define __LDBL_MIN__ 3.36210314311209350626e-4932L
+#define MMUEXT_PIN_L3_TABLE 2
+#define __WCHAR_TYPE__ int
+#define atomic_clear_32 atomic_clear_acq_32
+#define atomic_subtract_acq_long atomic_subtract_acq_64
+#define atomic_set_long atomic_set_64
+#define MMUEXT_TLB_FLUSH_ALL 10
+#define _GNTMAP_contains_pte (4)
+#define IA64_VEC_SPECULATION 27
+#define IA64_PSR_TB 0x0000000004000000
+#define IA64_FPSR_TRAP_VD UL_CONST(0x0000000000000001)
+#define ELIBEXEC 83
+#define PTE_PS_8K 13
+#define MAX_GUEST_CMDLINE 1024
+#define _ANSI_STDDEF_H 
+#define IA64_PSR_DA 0x0000004000000000
+#define atomic_add_rel_long atomic_add_rel_64
+#define ENOPKG 65
+#define _WCHAR_T_ 
+#define VIRQ_DEBUGGER 6
+#define EPERM 1
+#define EDOTDOT 73
+#define _STDDEF_H 
+#define atomic_subtract_rel_short atomic_subtract_rel_16
+#define XENFEAT_pae_pgdir_above_4gb 4
+#define IA64_PKR_VALID (1 << IA64_PKR_V)
+#define EADDRNOTAVAIL 99
+#define __XEN_PUBLIC_VERSION_H__ 
+#define ETIME 62
+#define IO_PORTS_SIZE 0x0000000004000000UL
+#define IA64_VEC_UNALIGNED_REFERENCE 30
+#define PRI_xen_pfn "lx"
+#define IA64_DCR_DEFAULT (MOS_IA64_DCR_BE)
+#define __FLT_DIG__ 6
+#define rmb() mb()
+#define __FLT_MAX_10_EXP__ 38
+#define IA64_SF_PC UL_CONST(0x000c)
+#define _WCHAR_T_DECLARED 
+#define atomic_cmpset_acq_long atomic_cmpset_acq_64
+#define atomic_set_acq_short atomic_set_acq_16
+#define atomic_add_acq_short atomic_add_acq_16
+#define _IA64_CPU_H_ 
+#define IA64_ITIR_PPN 48
+#define xen_vga_console_info dom0_vga_console_info
+#define HYPERVISOR_callback_op xencomm_arch_callback_op
+#define XEN_IA64_DEBUG_FORCE_DB (1 << 14)
+#define MOS_USR_PSR (IA64_PSR_IC | IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | 
IA64_PSR_RT | MOS_IA64_PSR_BE | IA64_PSR_BN | IA64_PSR_CPL_USER | IA64_PSR_AC)
+#define IA64_PKR_V 0
+#define __HYPERVISOR_ia64_debug_op __HYPERVISOR_arch_2
+#define __INT_MAX__ 2147483647
+#define atomic_clear_char atomic_clear_8
+#define UL_CONST(x) x ##UL
+#define IA64_SF_RC UL_CONST(0x0030)
+#define IA64_PKR_MBZ0 4
+#define IA64_PKR_MBZ1 32
+#define __gnu_linux__ 1
+#define IA64_RSE_EAGER ((IA64_RSC_MODE_EA<<IA64_RSC_MODE) | (MOS_IA64_RSC_BE 
<< IA64_RSC_BE) )
+#define HYPERPRIVOP_SET_KR (HYPERPRIVOP_START + 0x11)
+#define GNTCOPY_dest_gref (1<<_GNTCOPY_dest_gref)
+#define XEN_IA64_DEBUG_ON_PAL (1 << 7)
+#define ENETDOWN 100
+#define EPROTONOSUPPORT 93
+#define UINT_MAX (~0U)
+#define _T_SIZE_ 
+#define VIRQ_CON_RING 8
+#define ENOTRECOVERABLE 131
+#define IA64_SF_TD UL_CONST(0x0040)
+#define atomic_set_rel_char atomic_set_rel_8
+#define XEN_IA64_DEBUG_ON_EFI (1 << 9)
+#define _ASSIGN_tlb_track 2
+#define EIO 5
+#define __FLT_MAX_EXP__ 128
+#define atomic_set_acq_int atomic_set_acq_32
+#define ENOSR 63
+#define ENETUNREACH 101
+#define EXDEV 18
+#define atomic_readandclear_long atomic_readandclear_64
+#define xchg xchg8
+#define __DECIMAL_DIG__ 21
+#define synch_cmpxchg(ptr,old,new) ((__typeof__(*(ptr)))__synch_cmpxchg((ptr), 
(unsigned long)(old), (unsigned long)(new), sizeof(*(ptr))))
+#define __DBL_MANT_DIG__ 53
+#define ___int_size_t_h 
+#define _GNTMAP_application_map (3)
+#define __restore_flags(x) do { vcpu_info_t *_vcpu; barrier(); _vcpu = 
&HYPERVISOR_shared_info->vcpu_info[smp_processor_id()]; if 
((_vcpu->evtchn_upcall_mask = (x)) == 0) { barrier(); if ( 
unlikely(SWAP(_vcpu->evtchn_upcall_pending)) ) force_evtchn_callback(); }} 
while (0)
+#define atomic_subtract_rel_int atomic_subtract_rel_32
+#define ECHILD 10
+#define IA64_RR_MBZ0 1
+#define GTF_transfer_completed (1U<<_GTF_transfer_completed)
+#define ___int_wchar_t_h 
+#define __WINT_TYPE__ unsigned int
+#define EDQUOT 122
+#define IA64_SF_WRE UL_CONST(0x0002)
+#define _T_PTRDIFF 
+#define __GNUC__ 3
+#define atomic_clear_rel_int atomic_clear_rel_32
+#define MOS_SYS_PSR (IA64_PSR_IC | IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | 
IA64_PSR_RT | MOS_IA64_PSR_BE | IA64_PSR_BN | IA64_PSR_CPL_KERN | IA64_PSR_AC)
+#define IA64_RR_RID_LEN 24
+#define IA64_DOM0VP_iounmap 4
+#define IA64_RR_PS_LEN 6
+#define HYPERPRIVOP_PTC_GA (HYPERPRIVOP_START + 0xd)
+#define offsetof(TYPE,MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#define __LDBL_MIN_EXP__ (-16381)
+#define atomic_clear_acq_char atomic_clear_acq_8
+#define XENVER_capabilities 3
+#define IA64_VEC_INST_ACCESS_RIGHTS 22
+#define IA64_VEC_IA32_EXCEPTION 45
+#define __HYPERVISOR_hvm_op 34
+#define XEN_GUEST_HANDLE_64(name) XEN_GUEST_HANDLE(name)
+#define XEN_PAGE_SIZE PAGE_SIZE
+#define __HYPERVISOR_event_channel_op __HYPERVISOR_event_channel_op_compat
+#define __HYPERVISOR_set_gdt 2
+#define EREMOTEIO 121
+#define IA64_DOM0VP_ioremap 0
+#define HVMOP_set_isa_irq_level 3
+#define IA64_VEC_TAKEN_BRANCH_TRAP 35
+#define ENOSPC 28
+#define IA64_FPSR_SF(i,v) ((v) << ((i)*13+6))
+#define ENOEXEC 8
+#define UVMF_FLUSHTYPE_MASK (3UL<<0)
+#define atomic_cmpset_64 atomic_cmpset_acq_64
+#define GNTTABOP_error_msgs { "okay", "undefined error", "unrecognised domain 
id", "invalid grant reference", "invalid mapping handle", "invalid virtual 
address", "invalid device address", "no spare translation slot in the I/O MMU", 
"permission denied", "bad page", "copy arguments cross page boundary" }
+#define BUFFER_IO_PAGE_SIZE XEN_PAGE_SIZE
+#define atomic_clear_8 atomic_clear_acq_8
+#define atomic_clear_acq_short atomic_clear_acq_16
+#define ELNRNG 48
+#define IA64_VEC_FLOATING_POINT_TRAP 33
+#define __HYPERVISOR_memory_op 12
+#define VIRQ_DEBUG 1
+#define PTE_AR_RWX 3
+#define IA64_RSC_MODE_EA (0x3)
+#define XENMEM_populate_physmap 6
+#define SCHEDOP_poll 3
+#define __LDBL_MAX_10_EXP__ 4932
+#define XEN_CAPABILITIES_INFO_LEN (sizeof(xen_capabilities_info_t))
+#define XENMEM_maximum_ram_page 2
+#define __save_and_cli(x) do { vcpu_info_t *_vcpu; _vcpu = 
&HYPERVISOR_shared_info->vcpu_info[smp_processor_id()]; (x) = 
SWAP(_vcpu->evtchn_upcall_mask); _vcpu->evtchn_upcall_mask = SWAP(1); 
barrier(); } while (0)
+#define __DBL_EPSILON__ 2.2204460492503131e-16
+#define EVTCHNSTAT_unbound 1
+#define IA64_VEC_DIRTY_BIT 8
+#define get_xen_guest_handle(val,hnd) do { val = (hnd).p; } while (0)
+#define _SIZET_ 
+#define __HYPERVISOR_update_descriptor 10
+#define XEN_IA64_DEBUG_ON_PRIVOP (1 << 6)
+#define _LP64 1
+#define BUFFER_PIO_PAGE_START (BUFFER_IO_PAGE_START + BUFFER_IO_PAGE_SIZE)
+#define DOMID_IO (0x7FF1U)
+#define EFBIG 27
+#define __DBL_MAX__ 1.7976931348623157e+308
+#define SHUTDOWN_suspend 2
+#define GNTTABOP_unmap_and_replace 7
+#define ESRCH 3
+#define IA64_SF_RC_NEAREST UL_CONST(0x0000)
+#define ECHRNG 44
+#define GTF_invalid (0U<<0)
+#define EHOSTDOWN 112
+#define UVMF_ALL (1UL<<2)
+#define GNTTABOP_dump_table 3
+#define __wchar_t__ 
+#define XEN_IA64_DEBUG_FORCE_SS (1 << 13)
+#define ECOMM 70
+#define XMAPPEDREGS_SIZE (1 << XMAPPEDREGS_SHIFT)
+#define XEN_VGATYPE_VESA_LFB 0x23
+#define UVMF_LOCAL (0UL<<2)
+#define EVTCHNOP_unmask 9
+#define XENVER_changeset 4
+#define ENOLCK 37
+#define PTE_PS_256M 28
+#define ENFILE 23
+#define IA64_VEC_DKEY_MISS 7
+#define PTE_AR_RW 2
+#define PTE_AR_RX 1
+#define XENMAPSPACE_shared_info 0
+#define STORE_PAGE_SIZE XEN_PAGE_SIZE
+#define _STDDEF_H_ 
+#define IO_PORTS_PADDR 0x00000ffffc000000UL
+#define _GTF_reading (3)
+#define HYPERPRIVOP_MAX (0x1a)
+#define ENOSYS 38
+#define EPIPE 32
+#define XEN_IA64_DEBUG_ON_RFI (1 << 10)
+#define IA64_RSC_MODE_LI (0x2)
+#define PTE_MA_SHIFT 2
+#define IA64_RSC_MODE_LY (0x0)
+#define IA64_RSC_MODE 0
+#define atomic_subtract_short atomic_subtract_16
+#define ENOTCONN 107
+#define _SIZE_T_DEFINED 
+#define GNTST_bad_dev_addr (-6)
+#define va_arg(v,l) __builtin_va_arg(v,l)
+#define GTF_readonly (1U<<_GTF_readonly)
+#define IA64_ITIR_KEY 8
+#define _WCHAR_T_DEFINED_ 
+#define IA64_DOM0VP_phystomach 1
+#define MMUEXT_FLUSH_CACHE 12
+#define EBADMSG 74
+#define IA64_DOM0VP_add_physmap 6
+#define GNTMAP_contains_pte (1<<_GNTMAP_contains_pte)
+#define atomic_set_acq_long atomic_set_acq_64
+#define GNTTABOP_setup_table 2
+#define VGCF_EXTRA_REGS (1UL << 1)
+#define IA64_VEC_GENERAL_EXCEPTION 24
+#define EPFNOSUPPORT 96
+#define ENOTSUP 150
+#define ESRMNT 69
+#define IA64_VEC_UNSUPP_DATA_REFERENCE 31
+#define BUFFER_IO_PAGE_START (STORE_PAGE_START + STORE_PAGE_SIZE)
+#define __HYPERVISOR_sched_op __HYPERVISOR_sched_op_compat
+#define DOMID_FIRST_RESERVED (0x7FF0U)
+#define local_irq_disable() __cli()
+#define atomic_cmpset_ptr atomic_cmpset_acq_ptr
+#define HYPERPRIVOP_SET_RR0_TO_RR4 (HYPERPRIVOP_START + 0x19)
+#define EDEADLOCK EDEADLK
+#define ECONNABORTED 103
+#define _SIZE_T 
+#define IA64_VEC_IA32_INTERRUPT 47
+#define EBFONT 59
+#define PTE_AR_SHIFT 9
+#define XENFEAT_auto_translated_physmap 2
+#define _TYPES_H_ 
+#define atomic_clear_rel_long atomic_clear_rel_64
+#define __DBL_MAX_EXP__ 1024
+#define IA64_ISR_ED 0x0000080000000000
+#define IA64_ISR_EI 0x0000060000000000
+#define HYPERPRIVOP_ITC_D (HYPERPRIVOP_START + 0x4)
+#define HYPERPRIVOP_ITC_I (HYPERPRIVOP_START + 0x5)
+#define IA64_RSC_MODE_SI (0x1)
+#define IA64_RSC_MBZ0 5
+#define IA64_RSC_MBZ1 30
+#define IA64_ISR_CODE 0x000000000000ffff
+#define PTE_OFF_ED 52
+#define MMUEXT_INVLPG_ALL 11
+#define __HYPERVISOR_vm_assist 21
+#define EREMOTE 66
+#define _VA_LIST_ 
+#define GTF_accept_transfer (2U<<0)
+#define PTE_PS_64K 16
+#define ETOOMANYREFS 109
+#define PTE_PS_64M 26
+#define atomic_clear_int atomic_clear_32
+#define _GCC_SIZE_T 
+#define EVTCHNOP_bind_vcpu 8
+#define VMASST_CMD_enable 0
+#define XEN_IA64_DEBUG_ON_KERN_SSTEP (1 << 0)
+#define IA64_ITIR_PS 2
+#define __HYPERVISOR_xenoprof_op 31
+#define IA64_VEC_IKEY_MISS 6
+#define atomic_clear_short atomic_clear_16
+#define XENVER_compile_info 2
+#define IA64_VEC_ALT_DTLB 4
+#define EISCONN 106
+#define __size_t__ 
+#define XENMEM_add_to_physmap 7
+#define __FLT_DENORM_MIN__ 1.40129846e-45F
+#define IA64_ISR_IR 0x0000004000000000
+#define IO_SAPIC_SIZE 0x100000
+#define ENONET 64
+#define EXFULL 54
+#define VIRQ_DOM_EXC 3
+#define _STDARG_H 
+#define atomic_cmpset_acq_int atomic_cmpset_acq_32
+#define NVRAM_START (GFW_START + 10 * MEM_M)
+#define __HYPERVISOR_iret 23
+#define _T_WCHAR 
+#define __LONG_LONG_MAX__ 9223372036854775807LL
+#define HYPERPRIVOP_SET_RR (HYPERPRIVOP_START + 0x10)
+#define _VA_LIST_T_H 
+#define _MACHINE_ATOMIC_H_ 
+#define _GTF_PAT (7)
+#define _WCHAR_T 
+#define _GNTCOPY_source_gref (0)
+#define atomic_readandclear_int atomic_readandclear_32
+#define IA64_DCR_MBZ1_V 0xffffffffffffULL
+#define IA64_PKR_KEY 8
+#define XENMEM_exchange 11
+#define PTE_D_SHIFT 6
+#define ENOPROTOOPT 92
+#define ASSIGN_nocache (1UL << _ASSIGN_nocache)
+#define XEN_VGATYPE_TEXT_MODE_3 0x03
+#define XEN_GUEST_HANDLE(name) __guest_handle_ ## name
+#define _GTF_PCD (6)
+#define __FLT_MAX__ 3.40282347e+38F
+#define XMAPPEDREGS_SHIFT 12
+#define DEFINE(sym,val) asm volatile("\n->" sym " %0 /* " #val " */": : "i" 
(val))
+#define VMASST_TYPE_pae_extended_cr3 3
+#define __HYPERVISOR_sysctl 35
+#define atomic_clear_acq_long atomic_clear_acq_64
+#define ENOTNAM 118
+#define atomic_subtract_acq_int atomic_subtract_acq_32
+#define EMFILE 24
+#define PTE_MA_WB 0
+#define IA64_ISR_NA 0x0000000800000000
+#define __HYPERVISOR_sched_op_compat 6
+#define __va_list__ 
+#define IA64_ISR_NI 0x0000008000000000
+#define XEN_IA64_DEBUG_ON_KERN_TBRANCH (1 << 2)
+#define IA64_SF_RC_NEGINF UL_CONST(0x0010)
+#define VGC_PRIVREGS_HVM (~(-2UL))
+#define atomic_clear_acq_int atomic_clear_acq_32
+#define _GCC_WCHAR_T 
+#define VIRQ_TBUF 4
+#define MMUEXT_NEW_BASEPTR 5
+#define PTE_P_SHIFT 0
+#define _GTF_transfer_committed (2)
+#define IA64_RR_RID 8
+#define IA64_PSR_IC_BIT 13
+#define _PTRDIFF_T 
+#define IA64_PSR_RI_0 0x0000000000000000
+#define IA64_PSR_RI_1 0x0000020000000000
+#define IA64_PSR_RI_2 0x0000040000000000
+#define ENOBUFS 105
+#define __mk_unsigned_long(x) x ## UL
+#define IA64_ITIR_KEY_LEN 24
+#define __GXX_ABI_VERSION 102
+#define IA64_ISR_W 0x0000000200000000
+#define __FLT_MIN_10_EXP__ (-37)
+#define VIRQ_ARCH_0 16
+#define VIRQ_ARCH_1 17
+#define VIRQ_ARCH_2 18
+#define VIRQ_ARCH_3 19
+#define VIRQ_ARCH_4 20
+#define VIRQ_ARCH_5 21
+#define VIRQ_ARCH_6 22
+#define VIRQ_ARCH_7 23
+#define IA64_ISR_X 0x0000000100000000
+#define IA64_FPSR_DEFAULT (IA64_FPSR_TRAP_VD | IA64_FPSR_TRAP_DD | 
IA64_FPSR_TRAP_ZD | IA64_FPSR_TRAP_OD | IA64_FPSR_TRAP_UD | IA64_FPSR_TRAP_ID | 
IA64_FPSR_SF(0, IA64_SF_DEFAULT) | IA64_FPSR_SF(1, (IA64_SF_DEFAULT | 
IA64_SF_TD | IA64_SF_WRE)) | IA64_FPSR_SF(2, (IA64_SF_DEFAULT | IA64_SF_TD)) | 
IA64_FPSR_SF(3, (IA64_SF_DEFAULT | IA64_SF_TD)))
+#define atomic_add_rel_int atomic_add_rel_32
+#define atomic_subtract_acq_short atomic_subtract_acq_16
+#define atomic_cmpset_int atomic_cmpset_32
+#define HYPERPRIVOP_SET_EFLAG (HYPERPRIVOP_START + 0x16)
+#define __FLT_MIN_EXP__ (-125)
+#define EL3HLT 46
+#define VIRQ_MCA_CMC VIRQ_ARCH_1
+#define EFAULT 14
+#define HYPERPRIVOP_RSM_BE (HYPERPRIVOP_START + 0x17)
+#define IA64_ITIR_PS_LEN 6
+#define __XEN_PUBLIC_EVENT_CHANNEL_H__ 
+#define IA64_ISR_RS 0x0000002000000000
+#define BUFFER_PIO_PAGE_SIZE XEN_PAGE_SIZE
+#define _T_SIZE 
+#define XEN_EXTRAVERSION_LEN (sizeof(xen_extraversion_t))
+#define NR_EVENT_CHANNELS (sizeof(unsigned long) * sizeof(unsigned long) * 64)
+#define EWOULDBLOCK EAGAIN
+#define ASSIGN_pgc_allocated (1UL << _ASSIGN_pgc_allocated)
+#define PTE_A_SHIFT 5
+#define IA64_ISR_SO 0x0000010000000000
+#define IA64_ISR_SP 0x0000001000000000
+#define GNTTABOP_query_size 6
+#define _p(_x) ((void *)(unsigned long)(_x))
+#define IO_SAPIC_START 0xfec00000UL
+#define va_end(v) __builtin_va_end(v)
+#define console_mfn console.domU.mfn
+#define PTE_D 1
+#define PTE_P 1
+#define GNTST_bad_virt_addr (-5)
+#define XENCOMM_INLINE_FLAG 0x8000000000000000UL
+#define __PTRDIFF_T 
+#define __GNUC_MINOR__ 3
+#define IA64_ITIR_MBZ1_LEN 16
+#define ENOCSI 50
+#define ASSIGN_writable (0UL << _ASSIGN_readonly)
+#define GNTMAP_device_map (1<<_GNTMAP_device_map)
+#define smp_processor_id() 0
+#define VIRQ_MCA_CPE VIRQ_ARCH_2
+#define ELIBBAD 80
+#define IA64_DOM0VP_expose_p2m 7
+#define ESTRPIPE 86
+#define _GNTMAP_host_map (1)
+#define ECONNREFUSED 111
+#define get_popcnt(x) ({ uint64_t num; asm ("popcnt %0=%1" : "=r" (num) : "r" 
(x)); num; })
+#define IA64_RSE_LAZY ((IA64_RSC_MODE_LY<<IA64_RSC_MODE) | (MOS_IA64_RSC_BE << 
IA64_RSC_BE) )
+#define IA64_VEC_SINGLE_STEP_TRAP 36
+#define EAGAIN 11
+#define XENMEM_set_memory_map 13
+#define PAGE_SIZE (1 << PAGE_SHIFT)
+#define __DBL_MAX_10_EXP__ 308
+#define PTE_AR_R_RW 4
+#define MMUEXT_UNPIN_TABLE 4
+#define PTE_PS_256K 18
+#define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L
+#define GNTST_bad_domain (-2)
+#define __DBL_MIN__ 2.2250738585072014e-308
+#define EADDRINUSE 98
+#define _VA_LIST 
+#define PIB_SIZE 0x200000
+#define IA64_FPSR_TRAP_DD UL_CONST(0x0000000000000002)
+#define EVTCHNOP_reset 10
+#define atomic_add_rel_char atomic_add_rel_8
+#define atomic_subtract_char atomic_subtract_8
+#define HVMSTUB_HYPERCALL_FW_START 0x802
+#define UVMF_MULTI (0UL<<2)
+#define IA64_VEC_DTLB 2
+#define XEN_IA64_OPTF_OFF 0x0
+#define GNTST_bad_gntref (-3)
+#define NVRAM_VALID_SIG 0x4650494e45584948
+#define XENMEM_machphys_mfn_list 5
+#define XEN_IA64_DEBUG_OP_GET_TC 3
+#define VMASST_TYPE_4gb_segments 0
+#define ELIBMAX 82
+#define __HYPERVISOR_ia64_fast_eoi __HYPERVISOR_arch_1
+#define EEXIST 17
+#define EUCLEAN 117
+#define __PTRDIFF_TYPE__ long int
+#define __HYPERVISOR_grant_table_op 20
+#define IA64_VEC_DATA_ACCESS 10
+#define IA64_ISR_VECTOR 0x0000000000ff0000
+#define __sti() do { vcpu_info_t *_vcpu; barrier(); _vcpu = 
&HYPERVISOR_shared_info->vcpu_info[smp_processor_id()]; 
_vcpu->evtchn_upcall_mask = 0; barrier(); if 
(unlikely(SWAP(_vcpu->evtchn_upcall_pending))) force_evtchn_callback(); } while 
(0)
+#define IA64_VEC_FLOATING_POINT_FAULT 32
+#define IO_PAGE_SIZE XEN_PAGE_SIZE
+#define __LP64__ 1
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#define EL2NSYNC 45
+#define atomic_clear_long atomic_clear_64
+#define MMUEXT_SET_LDT 13
+#define ENETRESET 102
+#define IA64_SF_I UL_CONST(0x1000)
+#define __HYPERVISOR_physdev_op_compat 19
+#define IA64_SF_O UL_CONST(0x0400)
+#define IA64_VEC_NESTED_DTLB 5
+#define IA64_SF_U UL_CONST(0x0800)
+#define IA64_SF_V UL_CONST(0x0080)
+#define IA64_SF_Z UL_CONST(0x0200)
+#define __HYPERVISOR_stack_switch 3
+#define VMASST_TYPE_writable_pagetables 2
+#define IA64_DOM0VP_EFP_ALLOC_PTE 0x1
+#define addr_to_mfn(ADDR) (((unsigned long)ADDR) >> PAGE_SHIFT)
+#define GNTMAP_application_map (1<<_GNTMAP_application_map)
+#define MMIO_SIZE (512 * MEM_M)
+#define __XEN_PUBLIC_MEMORY_H__ 
+#define PTE_OFF_MA 3
+#define EISDIR 21
+#define PTE_PS_1M 20
+#define ENOENT 2
+#define XENVER_guest_handle 8
+#define DOMID_SELF (0x7FF0U)
+#define IA64_FPSR_TRAP_ID UL_CONST(0x0000000000000020)
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#define atomic_set_rel_long atomic_set_rel_64
+#define VIRQ_XENOPROF 7
+#define XSI_SHIFT 14
+#define GNTMAP_readonly (1<<_GNTMAP_readonly)
+#define GNTST_bad_copy_arg (-10)
+#define XEN_IA64_OPTF_IDENT_MAP_REG7_BIT 0
+#define XENMEM_maximum_gpfn 14
+#define GNTST_okay (0)
+#define EBADSLT 57
+#define __WCHAR_T__ 
+#define __LDBL_MIN_10_EXP__ (-4931)
+#define EVTCHNOP_close 3
+#define EKEYREVOKED 128
+#define _ASSIGN_nocache 1
+#define atomic_subtract_int atomic_subtract_32
+#define __XEN_INTERFACE_VERSION__ 0x00000000
+#define atomic_add_short atomic_add_16
+#define atomic_cmpset_rel_int atomic_cmpset_rel_32
+#define IA64_SF_RC_TRUNC UL_CONST(0x0030)
+#define PTE_PS_4K 12
+#define PTE_PS_4M 22
+#define XENMEM_increase_reservation 0
+#define MAX_VMASST_TYPE 3
+#define EHOSTUNREACH 113
+#define IA64_RR_VAL(size,rid) (((size) << IA64_RR_PS) | ((rid) << IA64_RR_RID))
+#define NVRAM_SIZE (MEM_K * 64)
+#define GTF_permit_access (1U<<0)
+#define atomic_subtract_rel_char atomic_subtract_rel_8
+#define __REGISTER_PREFIX__ 
+#define _GCC_PTRDIFF_T 
+#define EVTCHNOP_bind_pirq 2
+#define EIDRM 43
+#define SHUTDOWN_reboot 1
+#define HYPERPRIVOP_ITR_D (HYPERPRIVOP_START + 0xe)
+#define __LDBL_DIG__ 18
+#define ENOTUNIQ 76
+#define _GTF_PWT (5)
+#define MOS_IA64_RSC_BE 0
+#define MEM_G (1UL << 30)
+#define MEM_K (1UL << 10)
+#define MEM_M (1UL << 20)
+#define IA64_VEC_ALT_ITLB 3
+#define mb() ia64_mf()
+#define IA64_SF_PC_0 UL_CONST(0x0000)
+#define IA64_SF_PC_1 UL_CONST(0x0004)
+#define IA64_SF_PC_2 UL_CONST(0x0008)
+#define IA64_SF_PC_3 UL_CONST(0x000c)
+#define XENFEAT_writable_page_tables 0
+#define IA64_RSC_MBZ1_V 0x3ffffffffULL
+#define ___int_ptrdiff_t_h 
+#define PTE_OFF_PPN 12
+#define IA64_FPSR_TRAP_OD UL_CONST(0x0000000000000008)
+#define SIF_PRIVILEGED (1<<0)
+#define GNTTABOP_map_grant_ref 0
+#define atomic_add_acq_char atomic_add_acq_8
+#define HYPERPRIVOP_GET_EFLAG (HYPERPRIVOP_START + 0x15)
+#define __NO_INLINE__ 1
+#define BIND_PIRQ__WILL_SHARE 1
+#define XENCOMM_INLINE_MASK 0xf800000000000000UL
+#define XENFEAT_supervisor_mode_kernel 3
+#define EOPNOTSUPP 95
+#define __HYPERVISOR_set_debugreg 8
+#define atomic_subtract_16 atomic_subtract_acq_16
+#define IA64_VEC_LOWER_PRIVILEGE_TRANSFER 34
+#define __HYPERVISOR_kexec_op 37
+#define SHUTDOWN_poweroff 0
+#define __FLT_MANT_DIG__ 24
+#define atomic_add_long atomic_add_64
+#define __WCHAR_T 
+#define IA64_DCR_DEFER_ALL 0x7f00
+#define __VERSION__ "3.3.5 (Debian 1:3.3.5-13)"
+#define IA64_DCR_MBZ0_V 0xf
+#define EMEDIUMTYPE 124
+#define LEGACY_IO_START (MMIO_START + MMIO_SIZE)
+#define XEN_IA64_DEBUG_ON_MMU (1 << 11)
+#define console_evtchn console.domU.evtchn
+#define STORE_PAGE_START (IO_PAGE_START + IO_PAGE_SIZE)
diff -r 092232fa1fbd extras/stubfw/asm-offset.s
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/asm-offset.s        Thu Nov 22 04:09:09 2007 +0100
@@ -0,0 +1,100 @@
+       .file   "asm-offset.c"
+       .pred.safe_across_calls p1-p5,p16-p63
+       .section        .rodata
+       .align 8
+       .type   __func__.0#, @object
+       .size   __func__.0#, 26
+__func__.0:
+       stringz "HYPERVISOR_grant_table_op"
+       .text
+       .align 16
+       .global main#
+       .proc main#
+main:
+       .prologue
+       .body
+#APP
+       
+->IA64_CB_UNAT 0 /* offsetof(struct ia64_cb_regs, unat) */
+       
+->IA64_CB_R1 16 /* offsetof(struct ia64_cb_regs, r1) */
+       
+->IA64_CB_R2 24 /* offsetof(struct ia64_cb_regs, r2) */
+       
+->IA64_CB_R3 32 /* offsetof(struct ia64_cb_regs, r3) */
+       
+->IA64_CB_R4 40 /* offsetof(struct ia64_cb_regs, r4) */
+       
+->IA64_CB_R5 48 /* offsetof(struct ia64_cb_regs, r5) */
+       
+->IA64_CB_R8 56 /* offsetof(struct ia64_cb_regs, r8) */
+       
+->IA64_CB_R9 64 /* offsetof(struct ia64_cb_regs, r9) */
+       
+->IA64_CB_R10 72 /* offsetof(struct ia64_cb_regs, r10) */
+       
+->IA64_CB_R11 80 /* offsetof(struct ia64_cb_regs, r11) */
+       
+->IA64_CB_R12 88 /* offsetof(struct ia64_cb_regs, r12) */
+       
+->IA64_CB_R13 96 /* offsetof(struct ia64_cb_regs, r13) */
+       
+->IA64_CB_R14 104 /* offsetof(struct ia64_cb_regs, r14) */
+       
+->IA64_CB_R15 112 /* offsetof(struct ia64_cb_regs, r15) */
+       
+->IA64_CB_PR 120 /* offsetof(struct ia64_cb_regs, pr) */
+       
+->IA64_CB_B0 128 /* offsetof(struct ia64_cb_regs, b0) */
+       
+->IA64_CB_B6 136 /* offsetof(struct ia64_cb_regs, b6) */
+       
+->IA64_CB_B7 144 /* offsetof(struct ia64_cb_regs, b7) */
+       
+->IA64_CB_FPSR 152 /* offsetof(struct ia64_cb_regs, fpsr) */
+       
+->IA64_CB_F6 160 /* offsetof(struct ia64_cb_regs, f6) */
+       
+->IA64_CB_F7 176 /* offsetof(struct ia64_cb_regs, f7) */
+       
+->IA64_CB_F8 192 /* offsetof(struct ia64_cb_regs, f8) */
+       
+->IA64_CB_F9 208 /* offsetof(struct ia64_cb_regs, f9) */
+       
+->IA64_CB_F10 224 /* offsetof(struct ia64_cb_regs, f10) */
+       
+->IA64_CB_F11 240 /* offsetof(struct ia64_cb_regs, f11) */
+       
+->IA64_CB_RSC 256 /* offsetof(struct ia64_cb_regs, rsc) */
+       
+->IA64_CB_PFS 264 /* offsetof(struct ia64_cb_regs, pfs) */
+       
+->IA64_CB_CCV 272 /* offsetof(struct ia64_cb_regs, ccv) */
+       
+->IA64_CB_CSD 288 /* offsetof(struct ia64_cb_regs, csd) */
+       
+->IA64_CB_SSD 280 /* offsetof(struct ia64_cb_regs, ssd) */
+       
+->IA64_CB_NATS 296 /* offsetof(struct ia64_cb_regs, nats) */
+       
+->IA64_CB_IP 304 /* offsetof(struct ia64_cb_regs, ip) */
+       
+->IA64_CB_PSR 312 /* offsetof(struct ia64_cb_regs, psr) */
+       
+->IA64_CB_CFM 320 /* offsetof(struct ia64_cb_regs, cfm) */
+       
+->IA64_CB_RSV 328 /* offsetof(struct ia64_cb_regs, rsv) */
+       
+->IA64_CB_BSPSTORE 336 /* offsetof(struct ia64_cb_regs, bspstore) */
+       
+->IA64_CB_RNAT 344 /* offsetof(struct ia64_cb_regs, rnat) */
+       
+->IA64_CB_NDIRTY 352 /* offsetof(struct ia64_cb_regs, ndirty) */
+       
+->IA64_CB_RBS 360 /* offsetof(struct ia64_cb_regs, rbs) */
+#NO_APP
+       mov r8 = r0
+       br.ret.sptk.many b0
+       ;;
+       .endp main#
+       .ident  "GCC: (GNU) 3.3.5 (Debian 1:3.3.5-13)"
diff -r 092232fa1fbd extras/stubfw/block-vbd.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/block-vbd.c Wed Nov 21 14:51:38 2007 +0100
@@ -0,0 +1,186 @@
+/*
+ * Block driver for RAW files
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "ioemu/vl.h"
+#include "ioemu/block_int.h"
+
+#if defined(DEBUG_BLOCK) && !defined(QEMU_TOOL)
+#define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0) \
+    { fprintf(logfile, formatCstr, ##args); fflush(logfile); } } while (0)
+#else
+#define DEBUG_BLOCK_PRINT(formatCstr, args...)
+#endif
+
+
+static int vbd_pread(BlockDriverState *bs, int64_t offset,
+                     uint8_t *buf, int count)
+{
+  struct vbd_info *info = bs->opaque;
+  unsigned long sect;
+  //unsigned char *obuf;
+  //unsigned int ocount;
+
+  sect = offset >> SECTOR_BITS;
+
+  //printf ("vbd_pread: sect=%lu count=%lu\n", sect, count >> SECTOR_BITS);
+
+  /* Sanity checks.  */
+  if (((unsigned long)buf) & SECTOR_MASK) {
+    printf ("vbd_pread: bad buffer (%p)\n", buf);
+    exit ();
+  }
+  if (offset & SECTOR_MASK) {
+    printf ("vbd_pread: bad offset (%ld)\n", offset);
+    exit ();
+  }
+  if (count & SECTOR_MASK) {
+    printf ("vbd_pread: bad count (%ld)\n", count);
+    exit ();
+  }
+
+  //printf ("vbd_pread: off=%lx (sec=%lu) count=%x\n", offset, sect, count);
+
+  while (count > 0) {
+    if (vbd_request (info, 0, sect, buf) != 0) {
+      printf ("vbd_request failed (sect=%lu)\n", sect);
+      return -EIO;
+    }
+
+    buf += SECTOR_SIZE;
+    count -= SECTOR_SIZE;
+    sect++;
+  }
+
+
+
+  return 0;
+}
+
+static int vbd_pwrite(BlockDriverState *bs, int64_t offset,
+                      const uint8_t *buf, int count)
+{
+  struct vbd_info *info = bs->opaque;
+  unsigned long sect;
+
+  sect = offset >> SECTOR_BITS;
+
+  /* Sanity checks.  */
+  if (((unsigned long)buf) & SECTOR_MASK) {
+    printf ("vbd_pread: bad buffer (%p)\n", buf);
+    exit ();
+  }
+  if (offset & SECTOR_MASK) {
+    printf ("vbd_pread: bad offset (%ld)\n", offset);
+    exit ();
+  }
+  if (count & SECTOR_MASK) {
+    printf ("vbd_pread: bad count (%ld)\n", count);
+    exit ();
+  }
+
+  //printf ("vbd_pwrite: off=%lx (sec=%lu) count=%x\n", offset, sect, count);
+
+  while (count > 0) {
+    if (vbd_request (info, 1, sect, (uint8_t *)buf) != 0)
+      return -EIO;
+
+    buf += SECTOR_SIZE;
+    count -= SECTOR_SIZE;
+    sect++;
+  }
+  return 0;
+}
+
+static void vbd_close(BlockDriverState *bs)
+{
+    printk ("vbd_close: not implemented\n");
+}
+
+static int64_t vbd_getlength(BlockDriverState *bs)
+{
+  struct vbd_info *info = bs->opaque;
+
+  return info->sectors * info->sector_size;
+}
+
+
+
+BlockDriver bdrv_vbd = {
+    "vbd",
+    0,
+    NULL, /* no probe for protocols */
+    NULL,
+    NULL,
+    NULL,
+    vbd_close,
+    NULL,
+    NULL,
+
+#if 0
+    .bdrv_aio_read = raw_aio_read,
+    .bdrv_aio_write = raw_aio_write,
+    .bdrv_aio_cancel = raw_aio_cancel,
+    .aiocb_size = sizeof(RawAIOCB),
+#endif
+    .protocol_name = "file",
+    .bdrv_pread = vbd_pread,
+    .bdrv_pwrite = vbd_pwrite,
+    .bdrv_getlength = vbd_getlength,
+};
+
+int bdrv_open_vbd(BlockDriverState *bs, struct vbd_info *info, int flags)
+{
+    bs->read_only = 0;
+    bs->is_temporary = 0;
+    bs->encrypted = 0;
+
+    pstrcpy(bs->filename, sizeof(bs->filename), info->node_name);
+    bs->drv = &bdrv_vbd;
+    bs->opaque = info;
+#if 0
+    bs->opaque = qemu_mallocz(drv->instance_size);
+    if (bs->opaque == NULL && drv->instance_size > 0)
+        return -1;
+#endif
+    bs->read_only = info->is_ro;
+    if (bs->drv->bdrv_getlength) {
+        bs->total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
+    }
+
+    printf ("bdrv_vbd: %s nsec=%ld\n", bs->filename, bs->total_sectors);
+
+    /* call the change callback */
+    bs->media_changed = 1;
+    if (bs->change_cb)
+        bs->change_cb(bs->change_opaque);
+
+    return 0;
+}
+
+extern void bdrv_register(BlockDriver *bdrv);
+
+void
+bdrv_init (void)
+{
+  bdrv_register (&bdrv_vbd);
+}
diff -r 092232fa1fbd extras/stubfw/callback.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/callback.h  Sun Nov 11 03:47:58 2007 +0100
@@ -0,0 +1,48 @@
+#include "ia64_cpu.h"
+#include "ia64_fpu.h"
+
+struct ia64_cb_regs {
+  unsigned long unat;
+  unsigned long _pad1;
+  unsigned long r1;
+  unsigned long r2;
+  unsigned long r3;
+  unsigned long r4;
+  unsigned long r5;
+  unsigned long r8;
+  unsigned long r9;
+  unsigned long r10;
+  unsigned long r11;
+  unsigned long r12;
+  unsigned long r13;
+  unsigned long r14;
+  unsigned long r15;
+  unsigned long pr;
+  unsigned long b0;
+  unsigned long b6;
+  unsigned long b7;
+  unsigned long fpsr;
+  ia64_fpreg_t  f6;
+  ia64_fpreg_t  f7;
+  ia64_fpreg_t  f8;
+  ia64_fpreg_t  f9;
+  ia64_fpreg_t  f10;
+  ia64_fpreg_t  f11;
+  unsigned long rsc;
+  unsigned long pfs;
+  unsigned long ccv;
+  unsigned long ssd;
+  unsigned long csd;
+  unsigned long nats;
+  unsigned long ip;
+  unsigned long psr;
+  unsigned long cfm;
+  unsigned long rsv;
+  unsigned long bspstore;
+  unsigned long rnat;
+  unsigned long ndirty;
+
+  unsigned long rbs[0];
+};
+
+  
diff -r 092232fa1fbd extras/stubfw/console.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/console.c   Wed Nov 21 16:09:36 2007 +0100
@@ -0,0 +1,336 @@
+#include "console.h"
+#include "types.h"
+#include "lib.h"
+#include "os.h"
+#include "events.h"
+#include "ioemu/vl.h"
+
+
+#define BUG_ON(cond)
+
+static int term_got_escape;
+static void mon_proc_byte(char c);
+static int term_escape_char = 0x01; /* ctrl-a is used for escape */
+
+static CharDriverState xc_chr;
+
+static struct xencons_interface *xencons_interface;
+static unsigned int xencons_evtchn;
+
+
+int xencons_ring_send_no_notify(const char *data, unsigned len)
+{      
+  int sent = 0;
+  struct xencons_interface *intf = xencons_interface;
+  XENCONS_RING_IDX cons, prod;
+  cons = intf->out_cons;
+  prod = intf->out_prod;
+  mb();
+  BUG_ON((prod - cons) > sizeof(intf->out));
+
+  while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
+    intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
+
+  wmb();
+  intf->out_prod = prod;
+    
+  return sent;
+}
+
+int xencons_ring_send(const char *data, unsigned len)
+{
+    int sent;
+    sent = xencons_ring_send_no_notify(data, len);
+    notify_remote_via_evtchn(xencons_evtchn);
+
+    return sent;
+}      
+
+void xencons_wait_send (void)
+{
+  XENCONS_RING_IDX cons, prod;
+  struct xencons_interface *intf = xencons_interface;
+
+  while (1) {
+    cons = intf->out_cons;
+    prod = intf->out_prod;
+    mb();
+    if ((prod - cons) < sizeof(intf->out))
+      break;
+    poll_evtchn (xencons_evtchn);
+  }
+}
+
+void xencons_input(evtchn_port_t port, void *unused)
+{
+  struct xencons_interface *intf = xencons_interface;
+  XENCONS_RING_IDX cons, prod;
+  char c;
+  
+  cons = intf->in_cons;
+  prod = intf->in_prod;
+  mb();
+  BUG_ON((prod - cons) > sizeof(intf->in));
+
+  /* We are currently polling on output.
+     No need to send an event if no input.  */
+  if (cons == prod)
+    return;
+
+  while (cons != prod) {
+    c = intf->in[MASK_XENCONS_IDX(cons,intf->in)];
+    if (term_got_escape)
+       mon_proc_byte (c);
+    else if (c == term_escape_char)
+       term_got_escape = 1;
+    else if (qemu_chr_can_read (&xc_chr))
+       qemu_chr_read (&xc_chr, &c, 1);
+    else
+       break;
+    cons++;
+  }
+
+  mb();
+  intf->in_cons = cons;
+
+  notify_remote_via_evtchn(xencons_evtchn);
+}
+
+void
+init_console (void *interface, int evtchn)
+{
+  /* Setup console.  */
+  xencons_interface = (struct xencons_interface*)interface;
+  xencons_evtchn = evtchn;
+  bind_evtchn (evtchn, xencons_input, NULL);
+
+  unmask_evtchn (xencons_evtchn);
+}
+
+/* MUX driver for serial I/O splitting */
+#define MAX_MUX 4
+typedef struct {
+    IOCanRWHandler *chr_can_read[MAX_MUX];
+    IOReadHandler *chr_read[MAX_MUX];
+    IOEventHandler *chr_event[MAX_MUX];
+    void *ext_opaque[MAX_MUX];
+    int mux_cnt;
+    int max_size;
+} MuxDriver;
+static MuxDriver mux_drv;
+
+extern int ioemu_trace;
+
+static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    int res;
+    int len_orig = len;
+
+#if 0
+    if (len == 1 && *buf == '\a') {
+      printk ("Got marker!");
+      //ioemu_trace = 1;
+    }
+#endif
+
+    while (1) {
+       res = xencons_ring_send (buf, len);
+       len -= res;
+       if (len == 0)
+           break;
+       buf += res;
+       xencons_wait_send ();
+    }
+    return len_orig;
+}
+
+static char *mux_help[] = {
+    "% h    print this help\n\r",
+    "% x    exit emulator\n\r",
+    "% s    save disk data back to file (if -snapshot)\n\r",
+    "% b    send break (magic sysrq)\n\r",
+    "% p    pci info\n\r",
+    "% c    switch between console and monitor\n\r",
+    "% %  sends %\n\r",
+    NULL
+};
+
+static void mux_print_help(CharDriverState *chr)
+{
+    int i, j;
+    char ebuf[15] = "Escape-Char";
+    char cbuf[50] = "\n\r";
+
+    if (term_escape_char > 0 && term_escape_char < 26) {
+        sprintf(cbuf,"\n\r");
+        sprintf(ebuf,"C-%c", term_escape_char - 1 + 'a');
+    } else {
+        sprintf(cbuf,"\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r", 
term_escape_char);
+    }
+    chr->chr_write(chr, cbuf, strlen(cbuf));
+    for (i = 0; mux_help[i] != NULL; i++) {
+        for (j=0; mux_help[i][j] != '\0'; j++) {
+            if (mux_help[i][j] == '%')
+                chr->chr_write(chr, ebuf, strlen(ebuf));
+            else
+                chr->chr_write(chr, &mux_help[i][j], 1);
+        }
+    }
+}
+
+static void mon_proc_byte(char c)
+{
+    CharDriverState *chr = &xc_chr;
+    switch(c) {
+    case '?':
+    case 'h':
+       mux_print_help(chr);
+       break;
+    case 'x':
+    {
+       char *term =  "QEMU: Terminated\n\r";
+       chr->chr_write(chr,term,strlen(term));
+       exit();
+       break;
+    }
+    case 's':
+#ifndef IOEMU
+    {
+       int i;
+       for (i = 0; i < MAX_DISKS; i++) {
+           if (bs_table[i])
+               bdrv_commit(bs_table[i]);
+       }
+       if (mtd_bdrv)
+           bdrv_commit(mtd_bdrv);
+    }
+#endif
+    break;
+    case 'b':
+       qemu_chr_event(chr, CHR_EVENT_BREAK);
+       break;
+    case 'c':
+       /* Switch to the next registered device */
+       chr->focus++;
+       if (chr->focus >= mux_drv.mux_cnt)
+           chr->focus = 0;
+       break;
+    case 'p':
+      pci_info ();
+      break;
+    }
+    term_got_escape = 0;
+}
+
+static int mux_chr_can_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    MuxDriver *d = chr->opaque;
+    if (d->chr_can_read[chr->focus])
+       return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]);
+    return 0;
+}
+
+static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
+{
+    CharDriverState *chr = opaque;
+    MuxDriver *d = chr->opaque;
+    int i;
+    for(i = 0; i < size; i++)
+       d->chr_read[chr->focus](d->ext_opaque[chr->focus], &buf[i], 1);
+}
+
+static void mux_chr_event(void *opaque, int event)
+{
+    CharDriverState *chr = opaque;
+    MuxDriver *d = chr->opaque;
+    int i;
+
+    /* Send the event to all registered listeners */
+    for (i = 0; i < d->mux_cnt; i++)
+        if (d->chr_event[i])
+            d->chr_event[i](d->ext_opaque[i], event);
+}
+
+static void mux_chr_update_read_handler(CharDriverState *chr)
+{
+    MuxDriver *d = chr->opaque;
+
+    printf ("mux_chr_update_read_handler: %p\n", chr);
+    if (d->mux_cnt >= MAX_MUX) {
+        printf("Cannot add I/O handlers, MUX array is full\n");
+        return;
+    }
+    d->ext_opaque[d->mux_cnt] = chr->handler_opaque;
+    d->chr_can_read[d->mux_cnt] = chr->chr_can_read;
+    d->chr_read[d->mux_cnt] = chr->chr_read;
+    d->chr_event[d->mux_cnt] = chr->chr_event;
+#if 0 /* Crash dom0!! -> infinite recursion.  */
+    /* Fix up the real driver with mux routines */
+    if (d->mux_cnt == 0) {
+      printf ("mux_chr_update_read_handler (1)\n");
+        qemu_chr_add_handlers(&xc_chr, mux_chr_can_read, mux_chr_read,
+                              mux_chr_event, chr);
+      printf ("mux_chr_update_read_handler (2)\n");
+    }
+#endif
+    chr->focus = d->mux_cnt;
+    d->mux_cnt++;
+}
+
+CharDriverState *qemu_chr_open_xc(void)
+{
+    CharDriverState *chr = &xc_chr;
+    MuxDriver *d = &mux_drv;
+
+    chr->chr_write = mux_chr_write;
+
+    chr->opaque = d;
+    chr->focus = -1;
+    qemu_chr_add_handlers(chr, mux_chr_can_read, mux_chr_read,
+                         mux_chr_event, chr);
+    chr->chr_update_read_handler = mux_chr_update_read_handler;
+    return chr;
+}
+
+
+void vprintf(const char *fmt, va_list args)
+{
+    static char   buf[1024];
+    char *p;
+    
+    (void)vsnprintf(buf, sizeof(buf), fmt, args);
+ 
+    for (p = buf; *p; p++)
+      {
+       if (*p == '\n')
+         xencons_ring_send_no_notify ("\r", 1);
+       xencons_ring_send_no_notify (p, 1);
+      }
+    notify_remote_via_evtchn(xencons_evtchn);
+}
+
+void printk(const char *fmt, ...)
+{
+    va_list       args;
+    va_start(args, fmt);
+    vprintf(fmt, args);
+    va_end(args);        
+}
+
+int printf(const char *fmt, ...)
+{
+    va_list       args;
+    va_start(args, fmt);
+    vprintf(fmt, args);
+    va_end(args);        
+    return 0;
+}
+
+void term_printf(const char *fmt, ...)
+{
+    va_list       args;
+    va_start(args, fmt);
+    vprintf(fmt, args);
+    va_end(args);
+}
diff -r 092232fa1fbd extras/stubfw/console.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/console.h   Thu Nov 15 03:39:57 2007 +0100
@@ -0,0 +1,10 @@
+#include "types.h"
+#include <xen/io/console.h>
+
+//extern int xencons_ring_send_no_notify(const char *data, unsigned len);
+extern int xencons_ring_send(const char *data, unsigned len);
+
+extern void xencons_wait_send (void);
+
+extern void init_console (void *interface, int evtchn);
+
diff -r 092232fa1fbd extras/stubfw/event-asm.S
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/event-asm.S Sun Nov 11 04:03:45 2007 +0100
@@ -0,0 +1,236 @@
+#include "asm-offset.h"
+       
+#define FILL_REGS(R1, R2) \
+       ld8.fill R1=[r18],-16;\
+       ld8.fill R2=[r17],-16;\
+       ;;
+
+#define FILL_FP_REGS(F1, F2) \
+       ldf.fill F1=[r17],32;\
+       ldf.fill F2=[r18],32;\
+       ;;
+
+#define CB(R) IA64_CB_##R
+       
+       .globl callback_entry
+       .align 32
+       .proc callback_entry
+callback_entry:        
+       // r17=buffer,
+       mov r18=ar.unat
+       ;;
+       st8 [r17]=r18,CB(R1)-CB(UNAT)   // ar.unat, ??
+       ;;
+       add r18=CB(R2)-CB(R1),r17
+       ;; 
+       .mem.offset 0,0
+       st8.spill [r17]=r1,CB(R3)-CB(R1)
+       .mem.offset 8,0
+       st8.spill [r18]=r2,CB(R4)-CB(R2)
+       ;;
+       .mem.offset 0,0
+       st8.spill [r17]=r3,CB(R5)-CB(R3)
+       .mem.offset 8,0
+       st8.spill [r18]=r4,CB(R8)-CB(R4)
+       ;;
+       .mem.offset 0,0
+       st8.spill [r17]=r5,CB(R9)-CB(R5)
+       .mem.offset 8,0
+       st8.spill [r18]=r8,CB(R10)-CB(R8)
+       ;;
+       mov r8=pr
+       .mem.offset 0,0
+       st8.spill [r17]=r9,CB(R11)-CB(R9)
+       .mem.offset 8,0
+       st8.spill [r18]=r10,CB(R12)-CB(R10)
+       ;;
+       mov r9=b0
+       .mem.offset 0,0
+       st8.spill [r17]=r11,CB(R13)-CB(R11)
+       .mem.offset 8,0
+       st8.spill [r18]=r12,CB(R14)-CB(R12)
+       ;;
+       mov r10=b6
+       .mem.offset 0,0
+       st8.spill [r17]=r13,CB(R15)-CB(R13)
+       .mem.offset 8,0
+       st8.spill [r18]=r14,CB(PR)-CB(R14)
+       ;;
+       mov r11=b7
+       .mem.offset 0,0
+       st8.spill [r17]=r15,CB(B0)-CB(R15)
+       .mem.offset 8,0
+       st8 [r18]=r8,CB(B6)-CB(PR)
+       ;;
+       mov r8=ar.fpsr
+       .mem.offset 0,0
+       st8 [r17]=r9,CB(B7)-CB(B0)
+       .mem.offset 8,0
+       st8 [r18]=r10,CB(FPSR)-CB(B6)
+       ;;
+       mov r9=ar.rsc
+       .mem.offset 0,0
+       st8 [r17]=r11,CB(F6)-CB(B7)
+       .mem.offset 8,0
+       st8 [r18]=r8,CB(F7)-CB(FPSR)
+       ;;
+       mov r10=ar.pfs
+       stf.spill [r17]=f6,CB(F8)-CB(F6)
+       stf.spill [r18]=f7,CB(F9)-CB(F7)
+       ;;
+       mov r11=ar.ccv
+       stf.spill [r17]=f8,CB(F10)-CB(F8)
+       stf.spill [r18]=f9,CB(F11)-CB(F9)
+       ;;
+       mov r8=ar.unat
+       stf.spill [r17]=f10,CB(RSC)-CB(F10)
+       stf.spill [r18]=f11,CB(PFS)-CB(F11)
+       ;;
+       // RSE in enforced lazy mode
+       mov ar.rsc=0 // lazy
+       .mem.offset 0,0
+       st8 [r17]=r9,CB(CCV)-CB(RSC)
+       .mem.offset 8,0
+       st8 [r18]=r10,CB(NATS)-CB(PFS)
+       ;;
+       mov r9=ar.csd
+       mov r10=ar.ssd
+       .mem.offset 0,0
+       st8 [r17]=r11,CB(CSD)-CB(CCV)
+       .mem.offset 8,0
+       st8 [r18]=r8,CB(SSD)-CB(NATS)
+       ;;
+       .mem.offset 0,0
+       st8 [r17]=r9,CB(IP)-CB(CSD)
+       .mem.offset 8,0
+       st8 [r18]=r10,CB(PSR)-CB(SSD)
+       ;;
+       mov r9=ar.bspstore
+       mov r8=ar.rnat
+       .mem.offset 0,0
+       st8 [r17]=r28,CB(CFM)-CB(IP)
+       .mem.offset 8,0
+       st8 [r18]=r29,CB(RSV)-CB(PSR)
+       ;;
+       .mem.offset 0,0
+       st8 [r17]=r30,CB(BSPSTORE)-CB(CFM)
+       .mem.offset 8,0
+       st8 [r18]=r31,CB(RNAT)-CB(RSV)
+       ;;
+       .mem.offset 0,0
+       st8 [r17]=r9,CB(NDIRTY)-CB(BSPSTORE)
+       .mem.offset 8,0
+       st8 [r18]=r8,CB(RBS)-CB(RNAT)
+       ;;
+       add r2=-CB(RBS),r18
+       mov ar.bspstore=r18     // the new bspstore
+       ;;
+       add r12=(1<<16)-16,r2   // 64KB stack
+       mov r11=ar.bsp
+       movl gp=__gp
+       ;;
+       sub r11=r11,r18 // ndirty bytes
+       mov ar.rsc=3 // eager
+       ;;
+       st8 [r17]=r11   // store ndirty
+       add r4=CB(UNAT)-CB(NDIRTY),r17
+       ;; 
+       alloc r15=ar.pfs,0,0,7,0
+       mov out0=r16            // cause
+       mov out1=r19
+       mov out2=r20
+       mov out3=r21
+       mov out4=r22
+       mov out5=r23
+       mov out6=r4
+       ;;
+       br.call.sptk.few rp = ia64_callback
+       ;;
+       alloc r15=ar.pfs,0,0,0,0
+       add r18=CB(BSPSTORE),r4
+       add r17=CB(NDIRTY),r4
+       mov r16=r8
+       ;;
+       mov r19=r9
+       mov r20=r10
+       ld8 r15=[r17],CB(RNAT)-CB(NDIRTY)       // ndirty
+       ;;
+       // RSE in enforced lazy mode
+       mov ar.rsc=0 // lazy
+       mov r21=r11
+       ld8 r9=[r18],CB(CFM)-CB(BSPSTORE)
+       ld8 r8=[r17],CB(RSV)-CB(RNAT)
+       shl r15=r15,16
+       ;;
+       mov ar.rsc=r15          // loadrs+lazy
+       ld8 r30=[r18],CB(IP)-CB(CFM)
+       ld8 r31=[r17],CB(PSR)-CB(RSV)
+       ;;
+       loadrs
+       ld8 r28=[r18],CB(CCV)-CB(IP)
+       ld8 r29=[r17],CB(NATS)-CB(PSR)
+       ;; 
+       mov ar.bspstore=r9
+       ld8 r10=[r18],CB(CSD)-CB(CCV)
+       ld8 r11=[r17],CB(SSD)-CB(NATS)
+       ;;
+       mov ar.unat=r11
+       mov ar.rnat=r8
+       mov ar.ccv=r10
+       ;;
+       ld8 r10=[r18],CB(RSC)-CB(CSD)
+       ld8 r11=[r17],CB(PFS)-CB(SSD)
+       ;;
+       mov ar.csd=r10
+       mov ar.ssd=r11
+       ld8 r8=[r18],CB(F10)-CB(RSC)
+       ld8 r9=[r17],CB(F11)-CB(PFS)
+       ;;
+       ldf.fill f10=[r18],CB(F8)-CB(F10)
+       ldf.fill f11=[r17],CB(F9)-CB(F11)
+       mov ar.rsc=r8
+       ;;
+       ldf.fill f8=[r18],CB(F6)-CB(F8)
+       ldf.fill f9=[r17],CB(F7)-CB(F9)
+       mov ar.pfs=r9
+       ;;
+       ldf.fill f6=[r18],CB(B7)-CB(F6)
+       ldf.fill f7=[r17],CB(FPSR)-CB(F7)
+       ;;
+       ld8 r8=[r18],CB(B0)-CB(B7)
+       ld8 r9=[r17],CB(B6)-CB(FPSR)
+       ;; 
+       mov b7=r8
+       ld8 r10=[r18],CB(R15)-CB(B0)
+       ld8 r11=[r17],CB(PR)-CB(B6)
+       mov ar.fpsr=r9
+       ;;
+       ld8.fill r15=[r18],CB(R13)-CB(R15)
+       ld8 r8=[r17],CB(R14)-CB(PR)
+       mov b0=r10
+       ;;
+       ld8.fill r13=[r18],CB(R11)-CB(R13)
+       ld8.fill r14=[r17],CB(R12)-CB(R14)
+       mov b6=r11
+       ;;
+       ld8.fill r11=[r18],CB(R9)-CB(R11)
+       ld8.fill r12=[r17],CB(R10)-CB(R12)
+       mov pr=r8
+       ;;
+       ld8.fill r9=[r18],CB(R5)-CB(R9)
+       ld8.fill r10=[r17],CB(R8)-CB(R10)
+       ;;
+       ld8.fill r5=[r18],CB(R3)-CB(R5)
+       ld8.fill r8=[r17],CB(R4)-CB(R8)
+       ;;
+       ld8.fill r3=[r18],CB(R1)-CB(R3)
+       ld8.fill r4=[r17],CB(R2)-CB(R4)
+       ;;
+       ld8.fill r1=[r18],CB(UNAT)-CB(R1)
+       ld8.fill r2=[r17]
+       ;;
+       ld8 r18=[r18]
+       ;;
+       mov ar.unat=r18
+       break 0x01 //HVMSTUB_HYPERPRIVOP_CALLBACK_RETURN
+       .endp callback_entry
diff -r 092232fa1fbd extras/stubfw/events.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/events.c    Thu Nov 15 03:38:38 2007 +0100
@@ -0,0 +1,200 @@
+#include "types.h"
+#include "lib.h"
+#include "os.h"
+#include "events.h"
+
+#define NR_EVS 1024
+
+/* this represents a event handler. Chaining or sharing is not allowed */
+typedef struct _ev_action_t {
+       evtchn_handler_t handler;
+       void *data;
+    u32 count;
+} ev_action_t;
+
+static ev_action_t ev_actions[NR_EVS];
+static void default_handler(evtchn_port_t port, void *data);
+
+static unsigned long bound_ports[NR_EVS/(8*sizeof(unsigned long))];
+
+void unbind_all_ports(void)
+{
+    int i;
+
+    for (i = 0; i < NR_EVS; i++)
+    {
+        if (test_and_clear_bit(i, bound_ports))
+        {
+            struct evtchn_close close;
+            mask_evtchn(i);
+            close.port = i;
+            HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
+        }
+    }
+}
+  
+/*
+ * Demux events to different handlers.
+ */
+static int do_event(evtchn_port_t port)
+{
+    ev_action_t  *action;
+    if (port >= NR_EVS) {
+        printk("Port number too large: %d\n", port);
+       goto out;
+    }
+
+    action = &ev_actions[port];
+    action->count++;
+
+    /* call the handler */
+    action->handler(port, action->data);
+
+ out:
+    clear_evtchn(port);
+
+    return 1;
+
+}
+
+evtchn_port_t bind_evtchn(evtchn_port_t port, evtchn_handler_t handler,
+                         void *data)
+{
+    if (ev_actions[port].handler != default_handler)
+        printk("WARN: Handler for port %d already registered, replacing\n",
+              port);
+
+    ev_actions[port].data = data;
+    wmb();
+    ev_actions[port].handler = handler;
+    
+    /* Finally unmask the port */
+    unmask_evtchn(port);
+    
+    return port;
+}
+
+void unbind_evtchn(evtchn_port_t port)
+{
+    if (ev_actions[port].handler == default_handler)
+       printk("WARN: No handler for port %d when unbinding\n", port);
+    ev_actions[port].handler = default_handler;
+    wmb();
+    ev_actions[port].data = NULL;
+}
+
+int bind_virq(uint32_t virq, evtchn_handler_t handler, void *data)
+{
+    evtchn_bind_virq_t op;
+
+    /* Try to bind the virq to a port */
+    op.virq = virq;
+    op.vcpu = smp_processor_id();
+    
+    if ( HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, &op) != 0 ) {
+       printk("Failed to bind virtual IRQ %d\n", virq);
+       return 1;
+    }
+    set_bit(op.port,bound_ports);
+    bind_evtchn(op.port, handler, data);
+    return 0;
+}
+
+/*
+ * Initially all events are without a handler and disabled
+ */
+void init_events(void)
+{
+    int i;
+    /* inintialise event handler */
+    for ( i = 0; i < NR_EVS; i++ ) {
+        ev_actions[i].handler = default_handler;
+        mask_evtchn(i);
+    }
+}
+
+static void default_handler(evtchn_port_t port, void *ignore)
+{
+    printk("[Port %d] - event received\n", port);
+}
+
+/* Create a port available to the pal for exchanging notifications.
+   Returns the result of the hypervisor call. */
+
+/* Unfortunate confusion of terminology: the port is unbound as far
+   as Xen is concerned, but we automatically bind a handler to it
+   from inside mini-os. */
+
+int evtchn_alloc_unbound(domid_t pal, evtchn_handler_t handler,
+                        void *data, evtchn_port_t *port)
+{
+    evtchn_alloc_unbound_t op;
+    op.dom = DOMID_SELF;
+    op.remote_dom = pal;
+    int err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &op);
+    if (err)
+       return err;
+    *port = bind_evtchn(op.port, handler, data);
+    return err;
+}
+
+/* Connect to a port so as to allow the exchange of notifications with
+   the pal. Returns the result of the hypervisor call. */
+
+int evtchn_bind_interdomain(domid_t pal, evtchn_port_t remote_port,
+                           evtchn_handler_t handler, void *data,
+                           evtchn_port_t *local_port)
+{
+    evtchn_bind_interdomain_t op;
+    op.remote_dom = pal;
+    op.remote_port = remote_port;
+    int err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, &op);
+    if (err)
+       return err;
+    set_bit(op.local_port,bound_ports);
+    evtchn_port_t port = op.local_port;
+    clear_evtchn(port);              /* Without, handler gets invoked now! */
+    *local_port = bind_evtchn(port, handler, data);
+    return err;
+}
+
+void do_hypervisor_callback(void)
+{
+    unsigned long  l1, l2, l1i, l2i;
+    unsigned int   port;
+    int            cpu = 0;
+    volatile shared_info_t *s = shared_info;
+    volatile vcpu_info_t   *vcpu_info = &s->vcpu_info[cpu];
+
+   
+    vcpu_info->evtchn_upcall_pending = 0;
+    /* NB. No need for a barrier here -- XCHG is a barrier on x86. */
+    l1 = xchg((unsigned long *)&vcpu_info->evtchn_pending_sel, 0);
+    while ( l1 != 0 )
+    {
+        l1i = __ffs(l1);
+        l1 &= ~(1 << l1i);
+        
+        while ( (l2 = active_evtchns(cpu, s, l1i)) != 0 )
+        {
+            l2i = __ffs(l2);
+            l2 &= ~(1 << l2i);
+
+            port = (l1i << 5) + l2i;
+           do_event (port);
+           clear_evtchn (port);
+        }
+    }
+}
+
+void
+poll_evtchn (evtchn_port_t port)
+{
+  evtchn_port_t p = port;
+  sched_poll_t poll;
+  
+  set_xen_guest_handle (poll.ports, &p);
+  poll.nr_ports = 1;
+  poll.timeout = 100000UL; //0000000UL;
+  HYPERVISOR_poll (&poll);
+}
diff -r 092232fa1fbd extras/stubfw/gnttab.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/gnttab.c    Sat Nov 17 02:53:17 2007 +0100
@@ -0,0 +1,197 @@
+/* 
+ ****************************************************************************
+ * (C) 2006 - Cambridge University
+ ****************************************************************************
+ *
+ *        File: gnttab.c
+ *      Author: Steven Smith (sos22@xxxxxxxxx) 
+ *     Changes: Grzegorz Milos (gm281@xxxxxxxxx)
+ *              
+ *        Date: July 2006
+ * 
+ * Environment: Xen Minimal OS
+ * Description: Simple grant tables implementation. About as stupid as it's
+ *  possible to be and still work.
+ *
+ ****************************************************************************
+ */
+#include "os.h"
+#include "lib.h"
+//#include "mm.h"
+#include "gnttab.h"
+
+#define NR_RESERVED_ENTRIES 8
+
+/* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */
+#ifdef __ia64__
+#define NR_GRANT_FRAMES 1
+#else
+#define NR_GRANT_FRAMES 4
+#endif
+#define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(grant_entry_t))
+
+static grant_entry_t *gnttab_table;
+static grant_ref_t gnttab_list[NR_GRANT_ENTRIES];
+
+static void
+put_free_entry(grant_ref_t ref)
+{
+    gnttab_list[ref] = gnttab_list[0];
+    gnttab_list[0]  = ref;
+
+}
+
+static grant_ref_t
+get_free_entry(void)
+{
+    grant_ref_t ref = gnttab_list[0];
+    if (ref != GRANT_INVALID_REF)
+       gnttab_list[0] = gnttab_list[ref];
+    return ref;
+}
+
+grant_ref_t
+gnttab_grant_access(domid_t domid, unsigned long frame, int readonly)
+{
+    grant_ref_t ref;
+
+    ref = get_free_entry();
+    if (ref == GRANT_INVALID_REF)
+       return GRANT_INVALID_REF;
+    gnttab_table[ref].frame = frame;
+    gnttab_table[ref].domid = domid;
+    wmb();
+    gnttab_table[ref].flags =
+       GTF_permit_access | (readonly ? GTF_readonly : 0);
+
+    return ref;
+}
+
+grant_ref_t
+gnttab_grant_transfer(domid_t domid, unsigned long pfn)
+{
+    grant_ref_t ref;
+
+    ref = get_free_entry();
+    gnttab_table[ref].frame = pfn;
+    gnttab_table[ref].domid = domid;
+    wmb();
+    gnttab_table[ref].flags = GTF_accept_transfer;
+
+    return ref;
+}
+
+int
+gnttab_end_access(grant_ref_t ref)
+{
+    u16 flags, nflags;
+
+    nflags = gnttab_table[ref].flags;
+    do {
+        if ((flags = nflags) & (GTF_reading|GTF_writing)) {
+            printk("WARNING: g.e. still in use!\n");
+            return 0;
+        }
+    } while ((nflags = synch_cmpxchg(&gnttab_table[ref].flags, flags, 0)) !=
+            flags);
+
+    put_free_entry(ref);
+    return 1;
+}
+
+unsigned long
+gnttab_end_transfer(grant_ref_t ref)
+{
+    unsigned long frame;
+    u16 flags;
+
+    while (!((flags = gnttab_table[ref].flags) & GTF_transfer_committed)) {
+        if (synch_cmpxchg(&gnttab_table[ref].flags, flags, 0) == flags) {
+            printk("Release unused transfer grant.\n");
+            put_free_entry(ref);
+            return 0;
+        }
+    }
+
+    /* If a transfer is in progress then wait until it is completed. */
+    while (!(flags & GTF_transfer_completed)) {
+        flags = gnttab_table[ref].flags;
+    }
+
+    /* Read the frame number /after/ reading completion status. */
+    rmb();
+    frame = gnttab_table[ref].frame;
+
+    put_free_entry(ref);
+
+    return frame;
+}
+
+void *
+alloc_pages (int nbr)
+{
+    static unsigned long start_addr = 0xff700000;
+    void *res;
+
+    res = (void *)start_addr;
+    start_addr += nbr * PAGE_SIZE;
+    if (start_addr >= 0xff800000) {
+      printk ("alloc_pages(%d): no more memory\n", nbr);
+      exit();
+    }
+    return res;
+}
+
+grant_ref_t
+gnttab_alloc_and_grant(void **map)
+{
+    void *res = alloc_pages (1);
+
+    return gnttab_grant_access(0, addr_to_mfn (res), 0);
+}
+
+static const char * const gnttabop_error_msgs[] = GNTTABOP_error_msgs;
+
+const char *
+gnttabop_error(int16_t status)
+{
+    status = -status;
+    if (status < 0 || status >= ARRAY_SIZE(gnttabop_error_msgs))
+       return "bad status";
+    else
+        return gnttabop_error_msgs[status];
+}
+
+#if 0
+xen_pfn_t
+gnttab_pfn_to_mfn (xen_pfn_t pfn)
+{
+    xen_pfn_t xpfn = pfn;
+    xen_translate_gpfn_list_t xlat;
+
+    xlat.domid = DOMID_SELF;
+    xlat.nr_gpfns = 1;
+    set_xen_guest_handle(xlat.gpfn_list, &xpfn);
+    HYPERCALL_translate_();
+}
+#endif
+
+void
+init_gnttab(void)
+{
+    struct gnttab_setup_table setup;
+    unsigned long frames[NR_GRANT_FRAMES];
+    int i;
+
+    gnttab_list[0] = GRANT_INVALID_REF;
+    for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++)
+        put_free_entry(i);
+
+    setup.dom = DOMID_SELF;
+    setup.nr_frames = NR_GRANT_FRAMES;
+    set_xen_guest_handle(setup.frame_list, frames);
+
+    HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
+    gnttab_table = (grant_entry_t*)(frames[0] << PAGE_SHIFT); /* IA64  */
+    printk("gnttab_table mapped at %p.\n", gnttab_table);
+}
diff -r 092232fa1fbd extras/stubfw/hobs.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/hobs.c      Sun Nov 11 02:08:36 2007 +0100
@@ -0,0 +1,197 @@
+#include "lib.h"
+
+#define PERROR(x)
+
+#define HOB_SIGNATURE         0x3436474953424f48        // "HOBSIG64"
+#define GFW_HOB_START         ((4UL<<30)-(14UL<<20))    // 4G - 14M
+#define GFW_HOB_SIZE          (1UL<<20)                 // 1M
+
+typedef struct {
+    unsigned long signature;
+    unsigned int  type;
+    unsigned int  length;
+} HOB_GENERIC_HEADER;
+
+/*
+ * INFO HOB is the first data data in one HOB list
+ * it contains the control information of the HOB list
+ */
+typedef struct {
+    HOB_GENERIC_HEADER  header;
+    unsigned long       length;    // current length of hob
+    unsigned long       cur_pos;   // current poisiton of hob
+    unsigned long       buf_size;  // size of hob buffer
+} HOB_INFO;
+
+typedef struct{
+    unsigned long start;
+    unsigned long size;
+} hob_mem_t;
+
+typedef enum {
+    HOB_TYPE_INFO=0,
+    HOB_TYPE_TERMINAL,
+    HOB_TYPE_MEM,
+    HOB_TYPE_PAL_BUS_GET_FEATURES_DATA,
+    HOB_TYPE_PAL_CACHE_SUMMARY,
+    HOB_TYPE_PAL_MEM_ATTRIB,
+    HOB_TYPE_PAL_CACHE_INFO,
+    HOB_TYPE_PAL_CACHE_PROT_INFO,
+    HOB_TYPE_PAL_DEBUG_INFO,
+    HOB_TYPE_PAL_FIXED_ADDR,
+    HOB_TYPE_PAL_FREQ_BASE,
+    HOB_TYPE_PAL_FREQ_RATIOS,
+    HOB_TYPE_PAL_HALT_INFO,
+    HOB_TYPE_PAL_PERF_MON_INFO,
+    HOB_TYPE_PAL_PROC_GET_FEATURES,
+    HOB_TYPE_PAL_PTCE_INFO,
+    HOB_TYPE_PAL_REGISTER_INFO,
+    HOB_TYPE_PAL_RSE_INFO,
+    HOB_TYPE_PAL_TEST_INFO,
+    HOB_TYPE_PAL_VM_SUMMARY,
+    HOB_TYPE_PAL_VM_INFO,
+    HOB_TYPE_PAL_VM_PAGE_SIZE,
+    HOB_TYPE_NR_VCPU,
+    HOB_TYPE_NVRAM,
+    HOB_TYPE_MAX
+} hob_type_t;
+
+static int hob_init(char  *buffer ,unsigned long buf_size);
+static int add_mem_hob(char* hob_buf, unsigned long dom_mem_size);
+static int add_vcpus_hob(char* hob_buf, unsigned long nr_vcpu);
+static int add_nvram_hob(void* hob_buf, unsigned long nvram_addr);
+
+static int
+hob_init(char *buffer, unsigned long buf_size)
+{
+    HOB_INFO *phit;
+    HOB_GENERIC_HEADER *terminal;
+
+    if (sizeof(HOB_INFO) + sizeof(HOB_GENERIC_HEADER) > buf_size) {
+        // buffer too small
+        return -1;
+    }
+
+    phit = (HOB_INFO*)buffer;
+    phit->header.signature = HOB_SIGNATURE;
+    phit->header.type = HOB_TYPE_INFO;
+    phit->header.length = sizeof(HOB_INFO);
+    phit->length = sizeof(HOB_INFO) + sizeof(HOB_GENERIC_HEADER);
+    phit->cur_pos = 0;
+    phit->buf_size = buf_size;
+
+    terminal = (HOB_GENERIC_HEADER*)(buffer + sizeof(HOB_INFO));
+    terminal->signature = HOB_SIGNATURE;
+    terminal->type = HOB_TYPE_TERMINAL;
+    terminal->length = sizeof(HOB_GENERIC_HEADER);
+
+    return 0;
+}
+
+/*
+ *  Add a new HOB to the HOB List.
+ *
+ *  hob_start  -  start address of hob buffer
+ *  type       -  type of the hob to be added
+ *  data       -  data of the hob to be added
+ *  data_size  -  size of the data
+ */
+static int
+hob_add(char* hob_start, int type, void* data, int data_size)
+{
+    HOB_INFO *phit;
+    HOB_GENERIC_HEADER *newhob, *tail;
+
+    phit = (HOB_INFO*)hob_start;
+
+    if (phit->length + data_size > phit->buf_size) {
+        // no space for new hob
+        return -1;
+    }
+
+    //append new HOB
+    newhob = (HOB_GENERIC_HEADER*)(hob_start + phit->length -
+                                   sizeof(HOB_GENERIC_HEADER));
+    newhob->signature = HOB_SIGNATURE;
+    newhob->type = type;
+    newhob->length = data_size + sizeof(HOB_GENERIC_HEADER);
+    memcpy((char*)newhob + sizeof(HOB_GENERIC_HEADER), data, data_size);
+
+    // append terminal HOB
+    tail = (HOB_GENERIC_HEADER*)(hob_start + phit->length + data_size);
+    tail->signature = HOB_SIGNATURE;
+    tail->type = HOB_TYPE_TERMINAL;
+    tail->length = sizeof(HOB_GENERIC_HEADER);
+
+    // adjust HOB list length
+    phit->length += sizeof(HOB_GENERIC_HEADER) + data_size;
+
+    return 0;
+}
+
+
+#define MIN(x, y) ((x) < (y)) ? (x) : (y)
+static int
+add_mem_hob(char* hob_buf, unsigned long dom_mem_size)
+{
+    hob_mem_t memhob;
+
+    // less than 3G
+    memhob.start = 0;
+    memhob.size = MIN(dom_mem_size, 0xC0000000);
+
+    if (hob_add(hob_buf, HOB_TYPE_MEM, &memhob, sizeof(memhob)) < 0)
+        return -1;
+
+    if (dom_mem_size > 0xC0000000) {
+        // 4G ~ 4G+remain
+        memhob.start = 0x100000000; //4G
+        memhob.size = dom_mem_size - 0xC0000000;
+        if (hob_add(hob_buf, HOB_TYPE_MEM, &memhob, sizeof(memhob)) < 0)
+            return -1;
+    }
+    return 0;
+}
+
+static int 
+add_vcpus_hob(char* hob_buf, unsigned long vcpus)
+{
+    return hob_add(hob_buf, HOB_TYPE_NR_VCPU, &vcpus, sizeof(vcpus));
+}
+
+static int
+add_nvram_hob(void *hob_buf, unsigned long nvram_addr)
+{
+    return hob_add(hob_buf, HOB_TYPE_NVRAM, &nvram_addr, sizeof(nvram_addr));
+}
+
+int
+build_hob(unsigned long dom_mem_size, unsigned long vcpus,
+         unsigned long nvram_addr)
+{
+    char* hob_buf = (char *)GFW_HOB_START;
+    unsigned long hob_buf_size = GFW_HOB_SIZE;
+
+    //Init HOB List
+    if (hob_init(hob_buf, hob_buf_size) < 0) {
+        PERROR("buffer too small");
+       return -1;
+    }
+
+    if (add_mem_hob(hob_buf,dom_mem_size) < 0) {
+        PERROR("Add memory hob failed, buffer too small");
+       return -1;
+    }
+
+    if (add_vcpus_hob(hob_buf, vcpus) < 0) {
+        PERROR("Add NR_VCPU hob failed, buffer too small");
+       return -1;
+    }
+
+    if (add_nvram_hob( hob_buf, nvram_addr ) < 0) {
+        PERROR("Add nvram hob failed, buffer too small");
+       return -1;
+    }
+
+    return 0;
+}
diff -r 092232fa1fbd extras/stubfw/include/atomic.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/include/atomic.h    Wed Nov 07 00:40:13 2007 +0100
@@ -0,0 +1,508 @@
+/*
+ * This code is mostly taken from FreeBSD machine/atomic.h
+ * Changes: Dietmar Hahn <dietmar.hahn@xxxxxxxxxxxxxxxxxxx>
+ *
+ ****************************************************************************
+ * Copyright (c) 1998 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _MACHINE_ATOMIC_H_
+#define _MACHINE_ATOMIC_H_
+
+/*
+ * Various simple arithmetic on memory which is atomic in the presence
+ * of interrupts and SMP safe.
+ */
+
+#if !defined(__ASSEMBLY__)
+
+#include <types.h>
+
+
+/*
+ * Everything is built out of cmpxchg.
+ */
+#define IA64_CMPXCHG(sz, sem, p, cmpval, newval, ret)          \
+       __asm __volatile (                                      \
+               "mov ar.ccv=%2;;\n\t"                           \
+               "cmpxchg" #sz "." #sem " %0=%4,%3,ar.ccv\n\t"   \
+               : "=r" (ret), "=m" (*p)                         \
+               : "r" (cmpval), "r" (newval), "m" (*p)          \
+               : "memory")
+
+
+/*
+ * Some common forms of cmpxch.
+ */
+
+static __inline uint8_t
+ia64_cmpxchg_acq_8(volatile uint8_t* p, uint8_t cmpval, uint8_t newval)
+{
+       uint8_t ret;
+
+       IA64_CMPXCHG(1, acq, p, cmpval, newval, ret);
+       return (ret);
+}
+
+static __inline uint16_t
+ia64_cmpxchg_acq_16(volatile uint16_t* p, uint16_t cmpval, uint16_t newval)
+{
+       uint16_t ret;
+
+       IA64_CMPXCHG(2, acq, p, cmpval, newval, ret);
+       return (ret);
+}
+
+static __inline uint32_t
+ia64_cmpxchg_acq_32(volatile uint32_t* p, uint32_t cmpval, uint32_t newval)
+{
+       uint32_t ret;
+
+       IA64_CMPXCHG(4, acq, p, cmpval, newval, ret);
+       return (ret);
+}
+
+static __inline uint32_t
+ia64_cmpxchg_rel_32(volatile uint32_t* p, uint32_t cmpval, uint32_t newval)
+{
+       uint32_t ret;
+
+       IA64_CMPXCHG(4, rel, p, cmpval, newval, ret);
+       return (ret);
+}
+
+static __inline uint64_t
+ia64_cmpxchg_acq_64(volatile uint64_t* p, uint64_t cmpval, uint64_t newval)
+{
+       uint64_t ret;
+
+       IA64_CMPXCHG(8, acq, p, cmpval, newval, ret);
+       return (ret);
+}
+
+static __inline uint64_t
+ia64_cmpxchg_rel_64(volatile uint64_t* p, uint64_t cmpval, uint64_t newval)
+{
+       uint64_t ret;
+
+       IA64_CMPXCHG(8, rel, p, cmpval, newval, ret);
+       return (ret);
+}
+
+#define ATOMIC_STORE_LOAD(type, width, size)                   \
+static __inline uint##width##_t                                \
+ia64_ld_acq_##width(volatile uint##width##_t* p)               \
+{                                                              \
+       uint##width##_t v;                                      \
+                                                               \
+       __asm __volatile ("ld" size ".acq %0=%1"                \
+                         : "=r" (v)                            \
+                         : "m" (*p)                            \
+                         : "memory");                          \
+       return (v);                                             \
+}                                                              \
+                                                               \
+static __inline uint##width##_t                                \
+atomic_load_acq_##width(volatile uint##width##_t* p)           \
+{                                                              \
+       uint##width##_t v;                                      \
+                                                               \
+       __asm __volatile ("ld" size ".acq %0=%1"                \
+                         : "=r" (v)                            \
+                         : "m" (*p)                            \
+                         : "memory");                          \
+       return (v);                                             \
+}                                                              \
+                                                               \
+static __inline uint##width##_t                                \
+atomic_load_acq_##type(volatile uint##width##_t* p)            \
+{                                                              \
+       uint##width##_t v;                                      \
+                                                               \
+       __asm __volatile ("ld" size ".acq %0=%1"                \
+                         : "=r" (v)                            \
+                         : "m" (*p)                            \
+                         : "memory");                          \
+       return (v);                                             \
+}                                                              \
+                                                               \
+static __inline void                                           \
+ia64_st_rel_##width(volatile uint##width##_t* p, uint##width##_t v)\
+{                                                              \
+       __asm __volatile ("st" size ".rel %0=%1"                \
+                         : "=m" (*p)                           \
+                         : "r" (v)                             \
+                         : "memory");                          \
+}                                                              \
+                                                               \
+static __inline void                                           \
+atomic_store_rel_##width(volatile uint##width##_t* p, uint##width##_t v)\
+{                                                              \
+       __asm __volatile ("st" size ".rel %0=%1"                \
+                         : "=m" (*p)                           \
+                         : "r" (v)                             \
+                         : "memory");                          \
+}                                                              \
+                                                               \
+static __inline void                                           \
+atomic_store_rel_##type(volatile uint##width##_t* p, uint##width##_t v)\
+{                                                              \
+       __asm __volatile ("st" size ".rel %0=%1"                \
+                         : "=m" (*p)                           \
+                         : "r" (v)                             \
+                         : "memory");                          \
+}
+
+ATOMIC_STORE_LOAD(char, 8, "1")
+ATOMIC_STORE_LOAD(short, 16, "2")
+ATOMIC_STORE_LOAD(int, 32, "4")
+ATOMIC_STORE_LOAD(long, 64, "8")
+
+#undef ATOMIC_STORE_LOAD
+
+#define IA64_ATOMIC(sz, type, name, width, op)                 \
+                                                                       \
+static __inline type                                                   \
+atomic_##name##_acq_##width(volatile type *p, type v)          \
+{                                                                      \
+       type old, ret;                                                  \
+       do {                                                            \
+               old = *p;                                               \
+               IA64_CMPXCHG(sz, acq, p, old, old op v, ret);   \
+       } while (ret != old);                                           \
+       return(ret);                                                    \
+}                                                                      \
+                                                                       \
+static __inline type                                                   \
+atomic_##name##_rel_##width(volatile type *p, type v)          \
+{                                                                      \
+       type old, ret;                                                  \
+       do {                                                            \
+               old = *p;                                               \
+               IA64_CMPXCHG(sz, rel, p, old, old op v, ret);   \
+       } while (ret != old);                                           \
+       return(ret);                                                    \
+}
+
+IA64_ATOMIC(1, uint8_t,  set,  8,      |)
+IA64_ATOMIC(2, uint16_t, set,  16,     |)
+IA64_ATOMIC(4, uint32_t, set,  32,     |)
+IA64_ATOMIC(8, uint64_t, set,  64,     |)
+
+IA64_ATOMIC(1, uint8_t,  clear,        8,      &~)
+IA64_ATOMIC(2, uint16_t, clear,        16,     &~)
+IA64_ATOMIC(4, uint32_t, clear,        32,     &~)
+IA64_ATOMIC(8, uint64_t, clear,        64,     &~)
+
+IA64_ATOMIC(1, uint8_t,  add,  8,      +)
+IA64_ATOMIC(2, uint16_t, add,  16,     +)
+IA64_ATOMIC(4, uint32_t, add,  32,     +)
+IA64_ATOMIC(8, uint64_t, add,  64,     +)
+
+IA64_ATOMIC(1, uint8_t,  subtract,     8,      -)
+IA64_ATOMIC(2, uint16_t, subtract,     16,     -)
+IA64_ATOMIC(4, uint32_t, subtract,     32,     -)
+IA64_ATOMIC(8, uint64_t, subtract,     64,     -)
+
+#undef IA64_ATOMIC
+#undef IA64_CMPXCHG
+
+#define atomic_set_8                   atomic_set_acq_8
+#define        atomic_clear_8                  atomic_clear_acq_8
+#define atomic_add_8                   atomic_add_acq_8
+#define        atomic_subtract_8               atomic_subtract_acq_8
+
+#define atomic_set_16                  atomic_set_acq_16
+#define        atomic_clear_16                 atomic_clear_acq_16
+#define atomic_add_16                  atomic_add_acq_16
+#define        atomic_subtract_16              atomic_subtract_acq_16
+
+#define atomic_set_32                  atomic_set_acq_32
+#define        atomic_clear_32                 atomic_clear_acq_32
+#define atomic_add_32                  atomic_add_acq_32
+#define        atomic_subtract_32              atomic_subtract_acq_32
+
+#define atomic_set_64                  atomic_set_acq_64
+#define        atomic_clear_64                 atomic_clear_acq_64
+#define atomic_add_64                  atomic_add_acq_64
+#define        atomic_subtract_64              atomic_subtract_acq_64
+
+#define atomic_set_char                        atomic_set_8
+#define atomic_clear_char              atomic_clear_8
+#define atomic_add_char                        atomic_add_8
+#define atomic_subtract_char           atomic_subtract_8
+#define atomic_set_acq_char            atomic_set_acq_8
+#define atomic_clear_acq_char          atomic_clear_acq_8
+#define atomic_add_acq_char            atomic_add_acq_8
+#define atomic_subtract_acq_char       atomic_subtract_acq_8
+#define atomic_set_rel_char            atomic_set_rel_8
+#define atomic_clear_rel_char          atomic_clear_rel_8
+#define atomic_add_rel_char            atomic_add_rel_8
+#define atomic_subtract_rel_char       atomic_subtract_rel_8
+
+#define atomic_set_short               atomic_set_16
+#define atomic_clear_short             atomic_clear_16
+#define atomic_add_short               atomic_add_16
+#define atomic_subtract_short          atomic_subtract_16
+#define atomic_set_acq_short           atomic_set_acq_16
+#define atomic_clear_acq_short         atomic_clear_acq_16
+#define atomic_add_acq_short           atomic_add_acq_16
+#define atomic_subtract_acq_short      atomic_subtract_acq_16
+#define atomic_set_rel_short           atomic_set_rel_16
+#define atomic_clear_rel_short         atomic_clear_rel_16
+#define atomic_add_rel_short           atomic_add_rel_16
+#define atomic_subtract_rel_short      atomic_subtract_rel_16
+
+#define atomic_set_int                 atomic_set_32
+#define atomic_clear_int               atomic_clear_32
+#define atomic_add_int                 atomic_add_32
+#define atomic_subtract_int            atomic_subtract_32
+#define atomic_set_acq_int             atomic_set_acq_32
+#define atomic_clear_acq_int           atomic_clear_acq_32
+#define atomic_add_acq_int             atomic_add_acq_32
+#define atomic_subtract_acq_int                atomic_subtract_acq_32
+#define atomic_set_rel_int             atomic_set_rel_32
+#define atomic_clear_rel_int           atomic_clear_rel_32
+#define atomic_add_rel_int             atomic_add_rel_32
+#define atomic_subtract_rel_int                atomic_subtract_rel_32
+
+#define atomic_set_long                        atomic_set_64
+#define atomic_clear_long              atomic_clear_64
+#define atomic_add_long                        atomic_add_64
+#define atomic_subtract_long           atomic_subtract_64
+#define atomic_set_acq_long            atomic_set_acq_64
+#define atomic_clear_acq_long          atomic_clear_acq_64
+#define atomic_add_acq_long            atomic_add_acq_64
+#define atomic_subtract_acq_long       atomic_subtract_acq_64
+#define atomic_set_rel_long            atomic_set_rel_64
+#define atomic_clear_rel_long          atomic_clear_rel_64
+#define atomic_add_rel_long            atomic_add_rel_64
+#define atomic_subtract_rel_long       atomic_subtract_rel_64
+
+/*
+ * Atomically compare the value stored at *p with cmpval and if the
+ * two values are equal, update the value of *p with newval. Returns
+ * zero if the compare failed, nonzero otherwise.
+ */
+static __inline int
+atomic_cmpset_acq_32(volatile uint32_t* p, uint32_t cmpval, uint32_t newval)
+{
+       return ia64_cmpxchg_acq_32(p, cmpval, newval) == cmpval;
+}
+
+static __inline int
+atomic_cmpset_rel_32(volatile uint32_t* p, uint32_t cmpval, uint32_t newval)
+{
+       return ia64_cmpxchg_rel_32(p, cmpval, newval) == cmpval;
+}
+
+/*
+ * Atomically compare the value stored at *p with cmpval and if the
+ * two values are equal, update the value of *p with newval. Returns
+ * zero if the compare failed, nonzero otherwise.
+ */
+static __inline int
+atomic_cmpset_acq_64(volatile uint64_t* p, uint64_t cmpval, uint64_t newval)
+{
+       return ia64_cmpxchg_acq_64(p, cmpval, newval) == cmpval;
+}
+
+static __inline int
+atomic_cmpset_rel_64(volatile uint64_t* p, uint64_t cmpval, uint64_t newval)
+{
+       return ia64_cmpxchg_rel_64(p, cmpval, newval) == cmpval;
+}
+
+#define atomic_cmpset_32               atomic_cmpset_acq_32
+#define atomic_cmpset_64               atomic_cmpset_acq_64
+#define        atomic_cmpset_int               atomic_cmpset_32
+#define        atomic_cmpset_long              atomic_cmpset_64
+#define atomic_cmpset_acq_int          atomic_cmpset_acq_32
+#define atomic_cmpset_rel_int          atomic_cmpset_rel_32
+#define atomic_cmpset_acq_long         atomic_cmpset_acq_64
+#define atomic_cmpset_rel_long         atomic_cmpset_rel_64
+
+static __inline int
+atomic_cmpset_acq_ptr(volatile void *dst, void *exp, void *src)
+{
+        return atomic_cmpset_acq_long((volatile u_long *)dst,
+                                     (u_long)exp, (u_long)src);
+}
+
+static __inline int
+atomic_cmpset_rel_ptr(volatile void *dst, void *exp, void *src)
+{
+        return atomic_cmpset_rel_long((volatile u_long *)dst,
+                                     (u_long)exp, (u_long)src);
+}
+
+#define        atomic_cmpset_ptr       atomic_cmpset_acq_ptr
+
+static __inline void *
+atomic_load_acq_ptr(volatile void *p)
+{
+       return (void *)atomic_load_acq_long((volatile u_long *)p);
+}
+
+static __inline void
+atomic_store_rel_ptr(volatile void *p, void *v)
+{
+       atomic_store_rel_long((volatile u_long *)p, (u_long)v);
+}
+
+#define IA64_ATOMIC_PTR(NAME)                          \
+static __inline void                                   \
+atomic_##NAME##_ptr(volatile void *p, uintptr_t v)     \
+{                                                      \
+       atomic_##NAME##_long((volatile u_long *)p, v);  \
+}                                                      \
+                                                       \
+static __inline void                                   \
+atomic_##NAME##_acq_ptr(volatile void *p, uintptr_t v) \
+{                                                      \
+       atomic_##NAME##_acq_long((volatile u_long *)p, v);\
+}                                                      \
+                                                       \
+static __inline void                                   \
+atomic_##NAME##_rel_ptr(volatile void *p, uintptr_t v) \
+{                                                      \
+       atomic_##NAME##_rel_long((volatile u_long *)p, v);\
+}
+
+IA64_ATOMIC_PTR(set)
+IA64_ATOMIC_PTR(clear)
+IA64_ATOMIC_PTR(add)
+IA64_ATOMIC_PTR(subtract)
+
+#undef IA64_ATOMIC_PTR
+
+static __inline uint32_t
+atomic_readandclear_32(volatile uint32_t* p)
+{
+       uint32_t val;
+       do {
+               val = *p;
+       } while (!atomic_cmpset_32(p, val, 0));
+       return val;
+}
+
+static __inline uint64_t
+atomic_readandclear_64(volatile uint64_t* p)
+{
+       uint64_t val;
+       do {
+               val = *p;
+       } while (!atomic_cmpset_64(p, val, 0));
+       return val;
+}
+
+#define atomic_readandclear_int        atomic_readandclear_32
+#define atomic_readandclear_long       atomic_readandclear_64
+
+
+/* Some bit operations */
+
+static inline void
+set_bit(int num, volatile void *addr)
+{
+       uint32_t bit, b, old, new;
+       volatile uint32_t *p;
+       p = (volatile uint32_t *) addr + (num >> 5);
+       b = 1 << (num & 31);
+       bit = b;
+       do
+       {
+               old = *p;
+               new = old | bit;
+       } while(ia64_cmpxchg_acq_32(p, old, new) != old);
+}
+
+static __inline__ void
+clear_bit(int num, volatile void *addr)
+{
+       uint32_t mask, m,  old, new;
+       volatile uint32_t *p;
+       p = (volatile uint32_t *) addr + (num >> 5);
+       m = ~(1 << (num & 31));
+       mask = m;
+       do {
+               old = *p;
+               new = old & mask;
+       } while (ia64_cmpxchg_acq_32(p, old, new) != old);
+}
+
+static __inline__ int
+test_bit(int num, const volatile void *addr)
+{
+       uint32_t val = 1;
+        return val & (((const volatile uint32_t *) addr)[num >> 5] >> (num & 
31));
+}
+
+/*
+ * test_and_set_bit - Set a bit and return its old value
+ * num: Bit to set
+ * addr: Address to count from
+ */
+static inline int
+test_and_set_bit (int num, volatile void *addr)
+{
+        uint32_t bit, b, old, new;
+        volatile uint32_t *m;
+
+        m = (volatile uint32_t *) addr + (num >> 5);
+        b = 1 << (num & 31);
+        bit = b;
+        do {
+                old = *m;
+                new = old | bit;
+        } while (ia64_cmpxchg_acq_32(m, old, new) != old);
+        return (old & bit) != 0;
+}
+
+/*
+ * test_and_clear_bit - Clear a bit and return its old value
+ * num: Bit to set
+ * addr: Address to count from
+ */
+static
+inline int test_and_clear_bit(int num, volatile unsigned long * addr)
+{
+        uint32_t bit, b, old, new;
+        volatile uint32_t* a;
+
+        a = (volatile uint32_t *) addr + (num >> 5);
+        b = ~(1 << (num & 31));
+        bit = b;
+        do {
+                old = *a;
+                new = old & bit;
+        } while (ia64_cmpxchg_acq_32(a, old, new) != old);
+        return (old & ~bit) != 0;
+}
+
+
+#endif /* !defined(__ASSEMBLY__) */
+
+#endif /* ! _MACHINE_ATOMIC_H_ */
diff -r 092232fa1fbd extras/stubfw/include/callback.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/include/callback.h  Thu Nov 08 04:43:55 2007 +0100
@@ -0,0 +1,43 @@
+#include "ia64_fpu.h"
+
+struct ia64_cb_regs {
+  unsigned long unat;
+  unsigned long _pad1;
+  unsigned long r1;
+  unsigned long r2;
+  unsigned long r3;
+  unsigned long r4;
+  unsigned long r5;
+  unsigned long r8;
+  unsigned long r9;
+  unsigned long r10;
+  unsigned long r11;
+  unsigned long r12;
+  unsigned long r13;
+  unsigned long r14;
+  unsigned long r15;
+  unsigned long pr;
+  unsigned long b0;
+  unsigned long b6;
+  unsigned long b7;
+  unsigned long fpsr;
+  ia64_fpreg_t  f6;
+  ia64_fpreg_t  f7;
+  ia64_fpreg_t  f8;
+  ia64_fpreg_t  f9;
+  ia64_fpreg_t  f10;
+  ia64_fpreg_t  f11;
+  unsigned long rsc;
+  unsigned long pfs;
+  unsigned long ccv;
+  unsigned long nats;
+  unsigned long ip;
+  unsigned long psr;
+  unsigned long cfm;
+  unsigned long rsv;
+  unsigned long bspstore;
+  unsigned long rnat;
+  unsigned long ndirty;
+};
+
+  
diff -r 092232fa1fbd extras/stubfw/include/ctype.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/include/ctype.h     Wed Nov 07 00:40:13 2007 +0100
@@ -0,0 +1,79 @@
+#ifndef _CTYPE_H
+#define _CTYPE_H
+
+/*
+ * NOTE! This ctype does not handle EOF like the standard C
+ * library is required to.
+ */
+
+#define _U     0x01    /* upper */
+#define _L     0x02    /* lower */
+#define _D     0x04    /* digit */
+#define _C     0x08    /* cntrl */
+#define _P     0x10    /* punct */
+#define _S     0x20    /* white space (space/lf/tab) */
+#define _X     0x40    /* hex digit */
+#define _SP    0x80    /* hard space (0x20) */
+
+
+unsigned char _ctype[] = {
+_C,_C,_C,_C,_C,_C,_C,_C,                        /* 0-7 */
+_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,         /* 8-15 */
+_C,_C,_C,_C,_C,_C,_C,_C,                        /* 16-23 */
+_C,_C,_C,_C,_C,_C,_C,_C,                        /* 24-31 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,                    /* 32-39 */
+_P,_P,_P,_P,_P,_P,_P,_P,                        /* 40-47 */
+_D,_D,_D,_D,_D,_D,_D,_D,                        /* 48-55 */
+_D,_D,_P,_P,_P,_P,_P,_P,                        /* 56-63 */
+_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,      /* 64-71 */
+_U,_U,_U,_U,_U,_U,_U,_U,                        /* 72-79 */
+_U,_U,_U,_U,_U,_U,_U,_U,                        /* 80-87 */
+_U,_U,_U,_P,_P,_P,_P,_P,                        /* 88-95 */
+_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,      /* 96-103 */
+_L,_L,_L,_L,_L,_L,_L,_L,                        /* 104-111 */
+_L,_L,_L,_L,_L,_L,_L,_L,                        /* 112-119 */
+_L,_L,_L,_P,_P,_P,_P,_C,                        /* 120-127 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                /* 128-143 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                /* 144-159 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
+_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
+_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
+_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
+_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
+_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */
+
+#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
+
+#define isalnum(c)     ((__ismask(c)&(_U|_L|_D)) != 0)
+#define isalpha(c)     ((__ismask(c)&(_U|_L)) != 0)
+#define iscntrl(c)     ((__ismask(c)&(_C)) != 0)
+#define isdigit(c)     ((__ismask(c)&(_D)) != 0)
+#define isgraph(c)     ((__ismask(c)&(_P|_U|_L|_D)) != 0)
+#define islower(c)     ((__ismask(c)&(_L)) != 0)
+#define isprint(c)     ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
+#define ispunct(c)     ((__ismask(c)&(_P)) != 0)
+#define isspace(c)     ((__ismask(c)&(_S)) != 0)
+#define isupper(c)     ((__ismask(c)&(_U)) != 0)
+#define isxdigit(c)    ((__ismask(c)&(_D|_X)) != 0)
+
+#define isascii(c) (((unsigned char)(c))<=0x7f)
+#define toascii(c) (((unsigned char)(c))&0x7f)
+
+static inline unsigned char __tolower(unsigned char c)
+{
+       if (isupper(c))
+               c -= 'A'-'a';
+       return c;
+}
+
+static inline unsigned char __toupper(unsigned char c)
+{
+       if (islower(c))
+               c -= 'a'-'A';
+       return c;
+}
+
+#define tolower(c) __tolower(c)
+#define toupper(c) __toupper(c)
+
+#endif
diff -r 092232fa1fbd extras/stubfw/include/err.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/include/err.h       Wed Nov 07 00:40:13 2007 +0100
@@ -0,0 +1,31 @@
+#ifndef _ERR_H
+#define _ERR_H
+
+#include <errno.h>
+
+/*
+ * Kernel pointers have redundant information, so we can use a
+ * scheme where we can return either an error code or a dentry
+ * pointer with the same return value.
+ *
+ * This should be a per-architecture thing, to allow different
+ * error and pointer decisions.
+ */
+#define IS_ERR_VALUE(x) ((x) > (unsigned long)-1000L)
+
+static inline void *ERR_PTR(long error)
+{
+       return (void *) error;
+}
+
+static inline long PTR_ERR(const void *ptr)
+{
+       return (long) ptr;
+}
+
+static inline long IS_ERR(const void *ptr)
+{
+       return IS_ERR_VALUE((unsigned long)ptr);
+}
+
+#endif /* _LINUX_ERR_H */
diff -r 092232fa1fbd extras/stubfw/include/errno-base.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/include/errno-base.h        Wed Nov 07 00:40:13 2007 +0100
@@ -0,0 +1,39 @@
+#ifndef _ERRNO_BASE_H
+#define _ERRNO_BASE_H
+
+#define        EPERM            1      /* Operation not permitted */
+#define        ENOENT           2      /* No such file or directory */
+#define        ESRCH            3      /* No such process */
+#define        EINTR            4      /* Interrupted system call */
+#define        EIO              5      /* I/O error */
+#define        ENXIO            6      /* No such device or address */
+#define        E2BIG            7      /* Argument list too long */
+#define        ENOEXEC          8      /* Exec format error */
+#define        EBADF            9      /* Bad file number */
+#define        ECHILD          10      /* No child processes */
+#define        EAGAIN          11      /* Try again */
+#define        ENOMEM          12      /* Out of memory */
+#define        EACCES          13      /* Permission denied */
+#define        EFAULT          14      /* Bad address */
+#define        ENOTBLK         15      /* Block device required */
+#define        EBUSY           16      /* Device or resource busy */
+#define        EEXIST          17      /* File exists */
+#define        EXDEV           18      /* Cross-device link */
+#define        ENODEV          19      /* No such device */
+#define        ENOTDIR         20      /* Not a directory */
+#define        EISDIR          21      /* Is a directory */
+#define        EINVAL          22      /* Invalid argument */
+#define        ENFILE          23      /* File table overflow */
+#define        EMFILE          24      /* Too many open files */
+#define        ENOTTY          25      /* Not a typewriter */
+#define        ETXTBSY         26      /* Text file busy */
+#define        EFBIG           27      /* File too large */
+#define        ENOSPC          28      /* No space left on device */
+#define        ESPIPE          29      /* Illegal seek */
+#define        EROFS           30      /* Read-only file system */
+#define        EMLINK          31      /* Too many links */
+#define        EPIPE           32      /* Broken pipe */
+#define        EDOM            33      /* Math argument out of domain of func 
*/
+#define        ERANGE          34      /* Math result not representable */
+
+#endif
diff -r 092232fa1fbd extras/stubfw/include/errno.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/include/errno.h     Thu Nov 15 02:10:03 2007 +0100
@@ -0,0 +1,110 @@
+#ifndef _ERRNO_H
+#define _ERRNO_H
+
+#include <errno-base.h>
+
+#define        EDEADLK         35      /* Resource deadlock would occur */
+#define        ENAMETOOLONG    36      /* File name too long */
+#define        ENOLCK          37      /* No record locks available */
+#define        ENOSYS          38      /* Function not implemented */
+#define        ENOTEMPTY       39      /* Directory not empty */
+#define        ELOOP           40      /* Too many symbolic links encountered 
*/
+#define        EWOULDBLOCK     EAGAIN  /* Operation would block */
+#define        ENOMSG          42      /* No message of desired type */
+#define        EIDRM           43      /* Identifier removed */
+#define        ECHRNG          44      /* Channel number out of range */
+#define        EL2NSYNC        45      /* Level 2 not synchronized */
+#define        EL3HLT          46      /* Level 3 halted */
+#define        EL3RST          47      /* Level 3 reset */
+#define        ELNRNG          48      /* Link number out of range */
+#define        EUNATCH         49      /* Protocol driver not attached */
+#define        ENOCSI          50      /* No CSI structure available */
+#define        EL2HLT          51      /* Level 2 halted */
+#define        EBADE           52      /* Invalid exchange */
+#define        EBADR           53      /* Invalid request descriptor */
+#define        EXFULL          54      /* Exchange full */
+#define        ENOANO          55      /* No anode */
+#define        EBADRQC         56      /* Invalid request code */
+#define        EBADSLT         57      /* Invalid slot */
+
+#define        EDEADLOCK       EDEADLK
+
+#define        EBFONT          59      /* Bad font file format */
+#define        ENOSTR          60      /* Device not a stream */
+#define        ENODATA         61      /* No data available */
+#define        ETIME           62      /* Timer expired */
+#define        ENOSR           63      /* Out of streams resources */
+#define        ENONET          64      /* Machine is not on the network */
+#define        ENOPKG          65      /* Package not installed */
+#define        EREMOTE         66      /* Object is remote */
+#define        ENOLINK         67      /* Link has been severed */
+#define        EADV            68      /* Advertise error */
+#define        ESRMNT          69      /* Srmount error */
+#define        ECOMM           70      /* Communication error on send */
+#define        EPROTO          71      /* Protocol error */
+#define        EMULTIHOP       72      /* Multihop attempted */
+#define        EDOTDOT         73      /* RFS specific error */
+#define        EBADMSG         74      /* Not a data message */
+#define        EOVERFLOW       75      /* Value too large for defined data 
type */
+#define        ENOTUNIQ        76      /* Name not unique on network */
+#define        EBADFD          77      /* File descriptor in bad state */
+#define        EREMCHG         78      /* Remote address changed */
+#define        ELIBACC         79      /* Can not access a needed shared 
library */
+#define        ELIBBAD         80      /* Accessing a corrupted shared library 
*/
+#define        ELIBSCN         81      /* .lib section in a.out corrupted */
+#define        ELIBMAX         82      /* Attempting to link in too many 
shared libraries */
+#define        ELIBEXEC        83      /* Cannot exec a shared library 
directly */
+#define        EILSEQ          84      /* Illegal byte sequence */
+#define        ERESTART        85      /* Interrupted system call should be 
restarted */
+#define        ESTRPIPE        86      /* Streams pipe error */
+#define        EUSERS          87      /* Too many users */
+#define        ENOTSOCK        88      /* Socket operation on non-socket */
+#define        EDESTADDRREQ    89      /* Destination address required */
+#define        EMSGSIZE        90      /* Message too long */
+#define        EPROTOTYPE      91      /* Protocol wrong type for socket */
+#define        ENOPROTOOPT     92      /* Protocol not available */
+#define        EPROTONOSUPPORT 93      /* Protocol not supported */
+#define        ESOCKTNOSUPPORT 94      /* Socket type not supported */
+#define        EOPNOTSUPP      95      /* Operation not supported on transport 
endpoint */
+#define        EPFNOSUPPORT    96      /* Protocol family not supported */
+#define        EAFNOSUPPORT    97      /* Address family not supported by 
protocol */
+#define        EADDRINUSE      98      /* Address already in use */
+#define        EADDRNOTAVAIL   99      /* Cannot assign requested address */
+#define        ENETDOWN        100     /* Network is down */
+#define        ENETUNREACH     101     /* Network is unreachable */
+#define        ENETRESET       102     /* Network dropped connection because 
of reset */
+#define        ECONNABORTED    103     /* Software caused connection abort */
+#define        ECONNRESET      104     /* Connection reset by peer */
+#define        ENOBUFS         105     /* No buffer space available */
+#define        EISCONN         106     /* Transport endpoint is already 
connected */
+#define        ENOTCONN        107     /* Transport endpoint is not connected 
*/
+#define        ESHUTDOWN       108     /* Cannot send after transport endpoint 
shutdown */
+#define        ETOOMANYREFS    109     /* Too many references: cannot splice */
+#define        ETIMEDOUT       110     /* Connection timed out */
+#define        ECONNREFUSED    111     /* Connection refused */
+#define        EHOSTDOWN       112     /* Host is down */
+#define        EHOSTUNREACH    113     /* No route to host */
+#define        EALREADY        114     /* Operation already in progress */
+#define        EINPROGRESS     115     /* Operation now in progress */
+#define        ESTALE          116     /* Stale NFS file handle */
+#define        EUCLEAN         117     /* Structure needs cleaning */
+#define        ENOTNAM         118     /* Not a XENIX named type file */
+#define        ENAVAIL         119     /* No XENIX semaphores available */
+#define        EISNAM          120     /* Is a named type file */
+#define        EREMOTEIO       121     /* Remote I/O error */
+#define        EDQUOT          122     /* Quota exceeded */
+
+#define        ENOMEDIUM       123     /* No medium found */
+#define        EMEDIUMTYPE     124     /* Wrong medium type */
+#define        ECANCELED       125     /* Operation Canceled */
+#define        ENOKEY          126     /* Required key not available */
+#define        EKEYEXPIRED     127     /* Key has expired */
+#define        EKEYREVOKED     128     /* Key has been revoked */
+#define        EKEYREJECTED    129     /* Key was rejected by service */
+
+/* for robust mutexes */
+#define        EOWNERDEAD      130     /* Owner died */
+#define        ENOTRECOVERABLE 131     /* State not recoverable */
+
+#define ENOTSUP         150
+#endif
diff -r 092232fa1fbd extras/stubfw/include/events.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/include/events.h    Fri Nov 16 03:46:33 2007 +0100
@@ -0,0 +1,90 @@
+/* -*-  Mode:C; c-basic-offset:4; tab-width:4 -*-
+ ****************************************************************************
+ * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
+ * (C) 2005 - Grzegorz Milos - Intel Reseach Cambridge
+ ****************************************************************************
+ *
+ *        File: events.h
+ *      Author: Rolf Neugebauer (neugebar@xxxxxxxxxxxxx)
+ *     Changes: Grzegorz Milos (gm281@xxxxxxxxx)
+ *              
+ *        Date: Jul 2003, changes Jun 2005
+ * 
+ * Environment: Xen Minimal OS
+ * Description: Deals with events on the event channels
+ *
+ ****************************************************************************
+ */
+
+#ifndef _EVENTS_H_
+#define _EVENTS_H_
+
+#include "xen/event_channel.h"
+
+extern volatile struct shared_info *shared_info;
+
+typedef void (*evtchn_handler_t)(evtchn_port_t, void *);
+
+/* prototypes */
+int bind_virq(uint32_t virq, evtchn_handler_t handler, void *data);
+evtchn_port_t bind_evtchn(evtchn_port_t port, evtchn_handler_t handler,
+                                                 void *data);
+void unbind_evtchn(evtchn_port_t port);
+void init_events(void);
+int evtchn_alloc_unbound(domid_t pal, evtchn_handler_t handler,
+                                                void *data, evtchn_port_t 
*port);
+int evtchn_bind_interdomain(domid_t pal, evtchn_port_t remote_port,
+                                                       evtchn_handler_t 
handler, void *data,
+                                                       evtchn_port_t 
*local_port);
+void unbind_all_ports(void);
+
+static inline int notify_remote_via_evtchn(evtchn_port_t port)
+{
+    evtchn_send_t op;
+    op.port = port;
+    return HYPERVISOR_event_channel_op(EVTCHNOP_send, &op);
+}
+
+
+#define active_evtchns(cpu,sh,idx)              \
+    ((sh)->evtchn_pending[idx] &                \
+     ~(sh)->evtchn_mask[idx])
+
+static inline void clear_evtchn(u32 port)
+{
+  volatile shared_info_t *s = shared_info;
+  synch_clear_bit(port, &s->evtchn_pending[0]);
+}
+
+static inline void mask_evtchn(u32 port)
+{
+    synch_set_bit(port, &shared_info->evtchn_mask[0]);
+}
+
+static inline void unmask_evtchn(u32 port)
+{
+  volatile shared_info_t *s = shared_info;
+  volatile vcpu_info_t *vcpu_info = &s->vcpu_info[smp_processor_id()];
+
+  synch_clear_bit(port, &s->evtchn_mask[0]);
+  
+  /*
+   * The following is basically the equivalent of 'hw_resend_irq'. Just like
+   * a real IO-APIC we 'lose the interrupt edge' if the channel is masked.
+   */
+  if (  synch_test_bit        (port,    &s->evtchn_pending[0]) && 
+       !synch_test_and_set_bit(port>>5, &vcpu_info->evtchn_pending_sel) )
+    {
+      vcpu_info->evtchn_upcall_pending = 1;
+#if 0
+      if ( !vcpu_info->evtchn_upcall_mask )
+                 force_evtchn_callback();
+#endif
+    }
+}
+
+extern void do_hypervisor_callback(void);
+
+extern void poll_evtchn (evtchn_port_t port);
+
+#endif /* _EVENTS_H_ */
diff -r 092232fa1fbd extras/stubfw/include/gnttab.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/include/gnttab.h    Sat Nov 17 02:51:02 2007 +0100
@@ -0,0 +1,20 @@
+#ifndef __GNTTAB_H__
+#define __GNTTAB_H__
+
+#include <xen/grant_table.h>
+
+#define GRANT_INVALID_REF ((grant_ref_t)-1)
+
+void *alloc_free_page (size_t len);
+void *alloc_pages (int nbr);
+
+void init_gnttab(void);
+grant_ref_t gnttab_alloc_and_grant(void **map);
+grant_ref_t gnttab_grant_access(domid_t domid, unsigned long frame,
+                               int readonly);
+grant_ref_t gnttab_grant_transfer(domid_t domid, unsigned long pfn);
+unsigned long gnttab_end_transfer(grant_ref_t gref);
+int gnttab_end_access(grant_ref_t ref);
+const char *gnttabop_error(int16_t status);
+
+#endif /* !__GNTTAB_H__ */
diff -r 092232fa1fbd extras/stubfw/include/hypercall-ia64.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/include/hypercall-ia64.h    Thu Nov 22 04:05:26 2007 +0100
@@ -0,0 +1,349 @@
+/******************************************************************************
+ * hypercall.h
+ * 
+ * Mini-OS-specific hypervisor handling for ia64.
+ * 
+ * Copyright (c) 2002-2004, K A Fraser
+ * Changes: Dietmar Hahn <dietmar.hahn@xxxxxxxxxxxxxxxxxx>
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __HYPERCALL_H__
+#define __HYPERCALL_H__
+
+#include "errno.h"     /* ENOSYS() */
+#include <xen/event_channel.h>
+#include <xen/grant_table.h>
+#include <xen/sched.h>
+#include <xen/version.h>
+#include <xen/memory.h>
+#include <xen/hvm/hvm_op.h>
+#include "lib.h"
+
+#define PAGE_SHIFT 14
+#define PAGE_SIZE (1 << PAGE_SHIFT)
+#define addr_to_mfn(ADDR) (((unsigned long)ADDR) >> PAGE_SHIFT)
+
+#define get_xen_guest_handle(val, hnd)  do { val = (hnd).p; } while (0)
+
+#ifndef _HYPERVISOR_H_
+# error "please don't include this file directly"
+#endif
+
+// See linux/compiler.h
+#define likely(x)       __builtin_expect(!!(x), 1)
+#define unlikely(x)     __builtin_expect(!!(x), 0)
+
+extern unsigned long __hypercall(unsigned long a1, unsigned long a2,
+                                 unsigned long a3, unsigned long a4,
+                                 unsigned long a5, unsigned long cmd);
+extern unsigned long __hvmstub_hypercall(unsigned long a1, unsigned long a2,
+                                        unsigned long a3, unsigned long a4,
+                                        unsigned long cmd);
+/*
+ * Assembler stubs for hyper-calls.
+ */
+
+#define _hypercall0(type, name)                                        \
+({                                                             \
+       long __res;                                             \
+       __res = __hypercall(0, 0, 0, 0, 0,                      \
+                           __HYPERVISOR_##name);               \
+       (type)__res;                                            \
+})
+
+#define _hypercall1(type, name, a1)                            \
+({                                                             \
+       long __res;                                             \
+       __res = __hypercall((unsigned long)a1,                  \
+                           0, 0, 0, 0, __HYPERVISOR_##name);   \
+       (type)__res;                                            \
+})
+
+#define _hypercall2(type, name, a1, a2)                                \
+({                                                             \
+       long __res;                                             \
+       __res = __hypercall((unsigned long)a1,                  \
+                           (unsigned long)a2,                  \
+                           0, 0, 0, __HYPERVISOR_##name);      \
+       (type)__res;                                            \
+})
+
+#define _hypercall3(type, name, a1, a2, a3)                    \
+({                                                             \
+       long __res;                                             \
+       __res = __hypercall((unsigned long)a1,                  \
+                           (unsigned long)a2,                  \
+                           (unsigned long)a3,                  \
+                           0, 0, __HYPERVISOR_##name);         \
+       (type)__res;                                            \
+})
+
+#define _hypercall4(type, name, a1, a2, a3, a4)                        \
+({                                                             \
+       long __res;                                             \
+       __res = __hypercall((unsigned long)a1,                  \
+                           (unsigned long)a2,                  \
+                           (unsigned long)a3,                  \
+                           (unsigned long)a4,                  \
+                           0, __HYPERVISOR_##name);            \
+       (type)__res;                                            \
+})
+
+#define _hypercall5(type, name, a1, a2, a3, a4, a5)            \
+({                                                             \
+       long __res;                                             \
+       __res = __hypercall((unsigned long)a1,                  \
+                           (unsigned long)a2,                  \
+                           (unsigned long)a3,                  \
+                           (unsigned long)a4,                  \
+                           (unsigned long)a5,                  \
+                           __HYPERVISOR_##name);               \
+       (type)__res;                                            \
+})
+
+
+struct xencomm_handle;
+
+/* Inline version.  To be used only on linear space (kernel space).  */
+static inline struct xencomm_handle *
+xencomm_create_inline(void *buffer)
+{
+       unsigned long paddr;
+
+       paddr = (unsigned long)buffer;
+       return (struct xencomm_handle *)(paddr | XENCOMM_INLINE_FLAG);
+}
+
+static inline int
+xencomm_arch_event_channel_op(int cmd, void *arg)
+{
+       int rc;
+       struct xencomm_handle *newArg;
+
+       newArg = xencomm_create_inline(arg);
+       rc = _hypercall2(int, event_channel_op, cmd, newArg);
+       return rc;
+}
+#define HYPERVISOR_event_channel_op xencomm_arch_event_channel_op
+
+static inline int
+xencomm_arch_xen_version(int cmd, struct xencomm_handle *arg)
+{
+       return _hypercall2(int, xen_version, cmd, arg);
+}
+
+static inline int
+xencomm_arch_xen_feature(int cmd, struct xencomm_handle *arg)
+{
+       struct xencomm_handle *newArg;
+
+       newArg = xencomm_create_inline(arg);
+       return _hypercall2(int, xen_version, cmd, newArg);
+}
+
+static inline int
+HYPERVISOR_xen_version(int cmd, void *arg)
+{
+       switch(cmd) {
+               case XENVER_version:
+                       return xencomm_arch_xen_version(cmd, 0);
+               case XENVER_get_features:
+                       return xencomm_arch_xen_feature(cmd, arg);
+               default:
+                       return -1;
+       }
+}
+
+static inline int
+xencomm_arch_console_io(int cmd, int count, char *str)
+{
+       struct xencomm_handle *newStr;
+
+       newStr = xencomm_create_inline(str);
+       return _hypercall3(int, console_io, cmd, count, newStr);
+}
+
+
+#define HYPERVISOR_console_io xencomm_arch_console_io
+
+static inline int
+xencomm_arch_sched_op(int cmd, void *arg)
+{
+       struct xencomm_handle *newArg;
+
+       newArg = xencomm_create_inline(arg);
+       return _hypercall2(int, sched_op, cmd, newArg);
+}
+
+#define HYPERVISOR_sched_op xencomm_arch_sched_op
+
+static inline int
+xencomm_arch_callback_op(int cmd, void *arg)
+{
+       struct xencomm_handle *newArg;
+
+       newArg = xencomm_create_inline(arg);
+       return _hypercall2(int, callback_op, cmd, newArg);
+}
+#define HYPERVISOR_callback_op xencomm_arch_callback_op
+
+static inline int
+HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count)
+{
+       switch (cmd) {
+       case GNTTABOP_map_grant_ref:
+               break;
+       case GNTTABOP_unmap_grant_ref:
+               break;
+       case GNTTABOP_setup_table:
+       {
+               struct gnttab_setup_table *setup = uop;
+               void *frame;
+
+               if (count != 1)
+                       return -EINVAL;
+               get_xen_guest_handle(frame, setup->frame_list);
+               set_xen_guest_handle(setup->frame_list,
+                                    (void *)xencomm_create_inline (frame));
+               break;
+       }
+       case GNTTABOP_dump_table:
+               break;
+       case GNTTABOP_transfer:
+               break;
+       case GNTTABOP_copy:
+               break;
+       default:
+               printk("%s: unknown mini grant table op %d\n", __func__, cmd);
+               exit ();
+       }
+
+       uop = xencomm_create_inline (uop);
+
+       return _hypercall3(int, grant_table_op, cmd, uop, count);
+}
+
+static inline int
+HYPERVISOR_opt_feature(void *arg)
+{
+       struct xencomm_handle *new_arg;
+
+       new_arg = xencomm_create_inline(arg);
+
+       return _hypercall1(int, opt_feature, new_arg);
+}
+
+static inline int
+HYPERVISOR_yield(
+       void)
+{
+       int rc = HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
+
+       return rc;
+}
+
+static inline int
+HYPERVISOR_block(
+       void)
+{
+       int rc = HYPERVISOR_sched_op(SCHEDOP_block, NULL);
+
+       return rc;
+}
+
+static inline int
+HYPERVISOR_poll(sched_poll_t *p)
+{
+  evtchn_port_t *ports;
+  get_xen_guest_handle(ports, p->ports);
+  set_xen_guest_handle (p->ports,
+                       (evtchn_port_t*)xencomm_create_inline (ports));
+  return HYPERVISOR_sched_op(SCHEDOP_poll, p);
+}
+
+static inline int
+xencomm_arch_hypercall_memory_op(unsigned int cmd, struct xencomm_handle *arg)
+{
+       return _hypercall2(int, memory_op, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_add_to_physmap(struct xen_add_to_physmap *xatp)
+{
+  return xencomm_arch_hypercall_memory_op(XENMEM_add_to_physmap,
+                                         xencomm_create_inline(xatp));
+}
+                               
+#define HVMSTUB_HYPERCALL_SET_CALLBACK 0x801
+     
+static inline int
+HYPERVISOR_HVMSTUB_set_callback(const void *func, void *buf)
+{
+  return __hvmstub_hypercall ((unsigned long)func, (unsigned long)buf,
+                             0, 0, HVMSTUB_HYPERCALL_SET_CALLBACK);
+}
+
+#define HVMSTUB_HYPERCALL_FW_START 0x802
+     
+static inline int
+HYPERVISOR_HVMSTUB_fw_start(unsigned long ip, unsigned long psr)
+{
+  return __hvmstub_hypercall (ip, psr,
+                             0, 0, HVMSTUB_HYPERCALL_FW_START);
+}
+
+static inline int
+HYPERVISOR_hvmop (int cmd, void *arg)
+{
+  return _hypercall2(int, hvm_op, cmd, xencomm_create_inline (arg));
+}
+
+static inline int
+HYPERVISOR_hvm_set_isa_irq_level(domid_t domid, int irq, int level)
+{
+  xen_hvm_set_isa_irq_level_t op;
+  op.domid = domid;
+  op.isa_irq = irq;
+  op.level = level;
+  return HYPERVISOR_hvmop (HVMOP_set_isa_irq_level, &op);
+}
+
+static inline int
+HYPERVISOR_hvm_set_pci_intx_level(domid_t domid,
+                                 int domain, int bus, int device, int intx,
+                                 int level)
+{
+  xen_hvm_set_pci_intx_level_t op;
+  op.domid = domid;
+  op.domain = domain;
+  op.bus = bus;
+  op.device = device;
+  op.intx = intx;
+  op.level = level;
+  return HYPERVISOR_hvmop (HVMOP_set_isa_irq_level, &op);
+}
+#endif /* __HYPERCALL_H__ */
diff -r 092232fa1fbd extras/stubfw/include/hypervisor.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/include/hypervisor.h        Tue Nov 13 01:32:03 2007 +0100
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * hypervisor.h
+ * 
+ * Hypervisor handling.
+ * 
+ *
+ * Copyright (c) 2002, K A Fraser
+ * Copyright (c) 2005, Grzegorz Milos
+ * Updates: Aravindh Puthiyaparambil <aravindh.puthiyaparambil@xxxxxxxxxx>
+ * Updates: Dietmar Hahn <dietmar.hahn@xxxxxxxxxxxxxxxxxxx> for ia64
+ */
+
+#ifndef _HYPERVISOR_H_
+#define _HYPERVISOR_H_
+
+#include <types.h>
+#include <xen/xen.h>
+#if defined(__i386__)
+#include <hypercall-x86_32.h>
+#elif defined(__x86_64__)
+#include <hypercall-x86_64.h>
+#elif defined(__ia64__)
+#include <hypercall-ia64.h>
+#else
+#error "Unsupported architecture"
+#endif
+
+#endif /* __HYPERVISOR_H__ */
diff -r 092232fa1fbd extras/stubfw/include/ia64_cpu.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/include/ia64_cpu.h  Wed Nov 07 00:40:13 2007 +0100
@@ -0,0 +1,776 @@
+/*
+ * Done by Dietmar Hahn <dietmar.hahn@xxxxxxxxxxxxxxxxxxx>
+ * This code is mostly taken from FreeBSD.
+ *
+ *
+ ****************************************************************************
+ * Copyright (c) 2000 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _IA64_CPU_H_
+#define _IA64_CPU_H_
+
+#include "ia64_fpu.h"
+
+/*
+ * Definition of Region Register bits (RR)
+ *
+ * RR bit field positions
+ */
+#define IA64_RR_VE             0
+#define IA64_RR_MBZ0           1
+#define IA64_RR_PS             2
+#define IA64_RR_PS_LEN         6
+#define IA64_RR_RID            8
+#define IA64_RR_RID_LEN                24
+#define IA64_RR_MBZ1           32
+
+#define IA64_RR_IDX_POS                61
+
+#define IA64_RR_VAL(size,rid) (((size) << IA64_RR_PS) | ((rid) << IA64_RR_RID))
+
+/*
+ * Define Protection Key Register (PKR)
+ *
+ * PKR bit field positions
+ */
+#define IA64_PKR_V             0
+#define IA64_PKR_WD            1
+#define IA64_PKR_RD            2
+#define IA64_PKR_XD            3
+#define IA64_PKR_MBZ0          4
+#define IA64_PKR_KEY           8
+#define IA64_PKR_KEY_LEN       24
+#define IA64_PKR_MBZ1          32
+
+#define IA64_PKR_VALID         (1 << IA64_PKR_V)
+
+
+/*
+ * ITIR bit field positions
+ */
+
+#define        IA64_ITIR_MBZ0          0
+#define        IA64_ITIR_PS            2
+#define        IA64_ITIR_PS_LEN        6
+#define        IA64_ITIR_KEY           8
+#define        IA64_ITIR_KEY_LEN       24
+#define        IA64_ITIR_MBZ1          32
+#define        IA64_ITIR_MBZ1_LEN      16
+#define        IA64_ITIR_PPN           48
+#define        IA64_ITIR_PPN_LEN       15
+#define        IA64_ITIR_MBZ2          63
+
+/*
+ * Definition of PSR and IPSR bits.
+ */
+#define IA64_PSR_BE            0x0000000000000002
+#define IA64_PSR_UP            0x0000000000000004
+#define IA64_PSR_AC            0x0000000000000008
+#define IA64_PSR_MFL           0x0000000000000010
+#define IA64_PSR_MFH_BIT       5
+#define IA64_PSR_MFH           (1 << IA64_PSR_MFH_BIT)
+#define IA64_PSR_UMASK         (IA64_PSR_BE | IA64_PSR_UP |    \
+                               IA64_PSR_AC | IA64_PSR_MFL |    \
+                               IA64_PSR_MFH)
+#define IA64_PSR_IC_BIT                13
+#define IA64_PSR_IC            (1<<IA64_PSR_IC_BIT) /*0x0000000000002000*/
+#define IA64_PSR_I_BIT         14
+#define IA64_PSR_I             (1<<IA64_PSR_I_BIT) /*0x0000000000004000*/
+#define IA64_PSR_PK            0x0000000000008000
+#define IA64_PSR_DT            0x0000000000020000
+#define IA64_PSR_DFL           0x0000000000040000
+#define IA64_PSR_DFH           0x0000000000080000
+#define IA64_PSR_SP            0x0000000000100000
+#define IA64_PSR_PP            0x0000000000200000
+#define IA64_PSR_DI            0x0000000000400000
+#define IA64_PSR_SI            0x0000000000800000
+#define IA64_PSR_DB            0x0000000001000000
+#define IA64_PSR_LP            0x0000000002000000
+#define IA64_PSR_TB            0x0000000004000000
+#define IA64_PSR_RT            0x0000000008000000
+#define IA64_PSR_CPL           0x0000000300000000
+#define IA64_PSR_CPL_KERN      0x0000000000000000
+#define IA64_PSR_CPL_1         0x0000000100000000
+#define IA64_PSR_CPL_2         0x0000000200000000
+#define IA64_PSR_CPL_USER      0x0000000300000000
+#define IA64_PSR_IS            0x0000000400000000
+#define IA64_PSR_MC            0x0000000800000000
+#define IA64_PSR_IT            0x0000001000000000
+#define IA64_PSR_ID            0x0000002000000000
+#define IA64_PSR_DA            0x0000004000000000
+#define IA64_PSR_DD            0x0000008000000000
+#define IA64_PSR_SS            0x0000010000000000
+#define IA64_PSR_RI            0x0000060000000000
+#define IA64_PSR_RI_0          0x0000000000000000
+#define IA64_PSR_RI_1          0x0000020000000000
+#define IA64_PSR_RI_2          0x0000040000000000
+#define IA64_PSR_RI_SHIFT      41
+#define IA64_PSR_ED            0x0000080000000000
+#define IA64_PSR_BN            0x0000100000000000
+#define IA64_PSR_IA            0x0000200000000000
+
+
+/* Endianess of mini-os. */
+#if defined(BIG_ENDIAN)
+#define MOS_IA64_PSR_BE        IA64_PSR_BE
+#else
+#define MOS_IA64_PSR_BE        0
+#endif
+
+#define STARTUP_PSR (IA64_PSR_IT | IA64_PSR_PK | \
+                    IA64_PSR_DT | IA64_PSR_RT | MOS_IA64_PSR_BE | \
+                    IA64_PSR_BN | IA64_PSR_CPL_KERN | IA64_PSR_AC)
+
+#define MOS_SYS_PSR (IA64_PSR_IC | IA64_PSR_I | IA64_PSR_IT | \
+                    IA64_PSR_DT | IA64_PSR_RT | MOS_IA64_PSR_BE | \
+                    IA64_PSR_BN | IA64_PSR_CPL_KERN | IA64_PSR_AC)
+
+#define MOS_USR_PSR (IA64_PSR_IC | IA64_PSR_I | IA64_PSR_IT | \
+                    IA64_PSR_DT | IA64_PSR_RT | MOS_IA64_PSR_BE | \
+                    IA64_PSR_BN | IA64_PSR_CPL_USER | IA64_PSR_AC)
+
+/*
+ * Definition of ISR bits.
+ */
+#define IA64_ISR_CODE  0x000000000000ffff
+#define IA64_ISR_VECTOR        0x0000000000ff0000
+#define IA64_ISR_X     0x0000000100000000
+#define IA64_ISR_W     0x0000000200000000
+#define IA64_ISR_R     0x0000000400000000
+#define IA64_ISR_NA    0x0000000800000000
+#define IA64_ISR_SP    0x0000001000000000
+#define IA64_ISR_RS    0x0000002000000000
+#define IA64_ISR_IR    0x0000004000000000
+#define IA64_ISR_NI    0x0000008000000000
+#define IA64_ISR_SO    0x0000010000000000
+#define IA64_ISR_EI    0x0000060000000000
+#define IA64_ISR_EI_0  0x0000000000000000
+#define IA64_ISR_EI_1  0x0000020000000000
+#define IA64_ISR_EI_2  0x0000040000000000
+#define IA64_ISR_ED    0x0000080000000000
+
+/*
+ * DCR bit positions
+ */
+#define IA64_DCR_PP            0
+#define IA64_DCR_BE            1
+#define IA64_DCR_LC            2
+#define IA64_DCR_MBZ0          4
+#define IA64_DCR_MBZ0_V                0xf
+#define IA64_DCR_DM            8
+#define IA64_DCR_DP            9
+#define IA64_DCR_DK            10
+#define IA64_DCR_DX            11
+#define IA64_DCR_DR            12
+#define IA64_DCR_DA            13
+#define IA64_DCR_DD            14
+#define IA64_DCR_DEFER_ALL     0x7f00
+#define IA64_DCR_MBZ1          2
+#define IA64_DCR_MBZ1_V                0xffffffffffffULL
+
+
+       /* Endianess of DCR register. */
+#if defined(BIG_ENDIAN)
+#define MOS_IA64_DCR_BE        (1 << IA64_DCR_BE)
+#else
+#define MOS_IA64_DCR_BE        (0 << IA64_DCR_BE)
+#endif
+
+#define IA64_DCR_DEFAULT (MOS_IA64_DCR_BE)
+
+/*
+ * Vector numbers for various ia64 interrupts.
+ */
+#define IA64_VEC_VHPT                          0
+#define IA64_VEC_ITLB                          1
+#define IA64_VEC_DTLB                          2
+#define IA64_VEC_ALT_ITLB                      3
+#define IA64_VEC_ALT_DTLB                      4
+#define IA64_VEC_NESTED_DTLB                   5
+#define IA64_VEC_IKEY_MISS                     6
+#define IA64_VEC_DKEY_MISS                     7
+#define IA64_VEC_DIRTY_BIT                     8
+#define IA64_VEC_INST_ACCESS                   9
+#define IA64_VEC_DATA_ACCESS                   10
+#define IA64_VEC_BREAK                         11
+#define IA64_VEC_EXT_INTR                      12
+#define IA64_VEC_PAGE_NOT_PRESENT              20
+#define IA64_VEC_KEY_PERMISSION                        21
+#define IA64_VEC_INST_ACCESS_RIGHTS            22
+#define IA64_VEC_DATA_ACCESS_RIGHTS            23
+#define IA64_VEC_GENERAL_EXCEPTION             24
+#define IA64_VEC_DISABLED_FP                   25
+#define IA64_VEC_NAT_CONSUMPTION               26
+#define IA64_VEC_SPECULATION                   27
+#define IA64_VEC_DEBUG                         29
+#define IA64_VEC_UNALIGNED_REFERENCE           30
+#define IA64_VEC_UNSUPP_DATA_REFERENCE         31
+#define IA64_VEC_FLOATING_POINT_FAULT          32
+#define IA64_VEC_FLOATING_POINT_TRAP           33
+#define IA64_VEC_LOWER_PRIVILEGE_TRANSFER      34
+#define IA64_VEC_TAKEN_BRANCH_TRAP             35
+#define IA64_VEC_SINGLE_STEP_TRAP              36
+#define IA64_VEC_IA32_EXCEPTION                        45
+#define IA64_VEC_IA32_INTERCEPT                        46
+#define IA64_VEC_IA32_INTERRUPT                        47
+
+/*
+ * Define hardware RSE Configuration Register
+ *
+ * RS Configuration (RSC) bit field positions
+ */
+
+#define IA64_RSC_MODE       0
+#define IA64_RSC_PL         2
+#define IA64_RSC_BE         4
+#define IA64_RSC_MBZ0       5
+#define IA64_RSC_MBZ0_V     0x3ff
+#define IA64_RSC_LOADRS     16
+#define IA64_RSC_LOADRS_LEN 14
+#define IA64_RSC_MBZ1       30
+#define IA64_RSC_MBZ1_V     0x3ffffffffULL
+
+/*
+ * RSC modes
+ */
+#define IA64_RSC_MODE_LY (0x0)                 /* Lazy */
+#define IA64_RSC_MODE_SI (0x1)                 /* Store intensive */
+#define IA64_RSC_MODE_LI (0x2)                 /* Load intensive */
+#define IA64_RSC_MODE_EA (0x3)                 /* Eager */
+
+/* RSE endian mode. */
+#if defined(BIG_ENDIAN)
+#define MOS_IA64_RSC_BE        1               /* Big endian rse. */
+#else
+#define MOS_IA64_RSC_BE        0               /* Little endian rse. */
+#endif
+
+#define IA64_RSE_EAGER ((IA64_RSC_MODE_EA<<IA64_RSC_MODE) |    \
+                          (MOS_IA64_RSC_BE << IA64_RSC_BE)     )
+
+#define IA64_RSE_LAZY ((IA64_RSC_MODE_LY<<IA64_RSC_MODE) |     \
+                          (MOS_IA64_RSC_BE << IA64_RSC_BE)     )
+
+
+
+#ifndef __ASSEMBLY__
+
+/* ia64 function descriptor and global pointer */
+struct ia64_fdesc
+{
+       uint64_t        func;
+       uint64_t        gp;
+};
+typedef struct ia64_fdesc ia64_fdesc_t;
+
+#define FDESC_FUNC(fn)  (((struct ia64_fdesc *) fn)->func)
+#define FDESC_GP(fn)    (((struct ia64_fdesc *) fn)->gp)
+
+
+/*
+ * Various special ia64 instructions.
+ */
+
+/*
+ * Memory Fence.
+ */
+static __inline void
+ia64_mf(void)
+{
+       __asm __volatile("mf" ::: "memory");
+}
+
+static __inline void
+ia64_mf_a(void)
+{
+       __asm __volatile("mf.a");
+}
+
+/*
+ * Flush Cache.
+ */
+static __inline void
+ia64_fc(uint64_t va)
+{
+       __asm __volatile("fc %0" :: "r"(va));
+}
+
+/*
+ * Sync instruction stream.
+ */
+static __inline void
+ia64_sync_i(void)
+{
+       __asm __volatile("sync.i");
+}
+
+/*
+ * Calculate address in VHPT for va.
+ */
+static __inline uint64_t
+ia64_thash(uint64_t va)
+{
+       uint64_t result;
+       __asm __volatile("thash %0=%1" : "=r" (result) : "r" (va));
+       return result;
+}
+
+/*
+ * Calculate VHPT tag for va.
+ */
+static __inline uint64_t
+ia64_ttag(uint64_t va)
+{
+       uint64_t result;
+       __asm __volatile("ttag %0=%1" : "=r" (result) : "r" (va));
+       return result;
+}
+
+/*
+ * Convert virtual address to physical.
+ */
+static __inline uint64_t
+ia64_tpa(uint64_t va)
+{
+       uint64_t result;
+       __asm __volatile("tpa %0=%1" : "=r" (result) : "r" (va));
+       return result;
+}
+
+/*
+ * Generate a ptc.e instruction.
+ */
+static __inline void
+ia64_ptc_e(uint64_t v)
+{
+       __asm __volatile("ptc.e %0;; srlz.d;;" :: "r"(v));
+}
+
+/*
+ * Generate a ptc.g instruction.
+ */
+static __inline void
+ia64_ptc_g(uint64_t va, uint64_t size)
+{
+       __asm __volatile("ptc.g %0,%1;; srlz.d;;" :: "r"(va), "r"(size<<2));
+}
+
+/*
+ * Generate a ptc.ga instruction.
+ */
+static __inline void
+ia64_ptc_ga(uint64_t va, uint64_t size)
+{
+       __asm __volatile("ptc.ga %0,%1;; srlz.d;;" :: "r"(va), "r"(size<<2));
+}
+
+/*
+ * Generate a ptc.l instruction.
+ */
+static __inline void
+ia64_ptc_l(uint64_t va, uint64_t size)
+{
+       __asm __volatile("ptc.l %0,%1;; srlz.d;;" :: "r"(va), "r"(size<<2));
+}
+
+/*
+ * Read the value of psr.
+ */
+static __inline uint64_t
+ia64_get_psr(void)
+{
+       uint64_t result;
+       __asm __volatile("mov %0=psr;;" : "=r" (result));
+       return result;
+}
+
+static __inline void
+ia64_set_psr(uint64_t v)
+{
+       __asm __volatile("mov psr.l=%0" :: "r" (v));
+}
+
+static __inline void
+ia64_srlz_d(void)
+{
+       __asm __volatile("srlz.d;;");
+}
+
+static __inline void
+disable_intr(void)
+{
+       __asm __volatile ("rsm psr.ic|psr.i");
+}
+
+static __inline void
+enable_intr(void)
+{
+       __asm __volatile ("ssm psr.ic|psr.i");
+}
+
+/*
+ * Define accessors for application registers.
+ */
+
+#define IA64_AR(name)                                                  \
+                                                                       \
+static __inline uint64_t                                               \
+ia64_get_##name(void)                                                  \
+{                                                                      \
+       uint64_t result;                                                \
+       __asm __volatile(";;mov %0=ar." #name ";;" : "=r" (result));    \
+       return result;                                                  \
+}                                                                      \
+                                                                       \
+static __inline void                                                   \
+ia64_set_##name(uint64_t v)                                            \
+{                                                                      \
+       __asm __volatile("mov ar." #name "=%0" :: "r" (v));             \
+}
+
+IA64_AR(k0)
+IA64_AR(k1)
+IA64_AR(k2)
+IA64_AR(k3)
+IA64_AR(k4)
+IA64_AR(k5)
+IA64_AR(k6)
+IA64_AR(k7)
+
+IA64_AR(rsc)
+IA64_AR(bsp)
+IA64_AR(bspstore)
+IA64_AR(rnat)
+
+IA64_AR(fcr)
+
+IA64_AR(eflag)
+IA64_AR(csd)
+IA64_AR(ssd)
+IA64_AR(cflg)
+IA64_AR(fsr)
+IA64_AR(fir)
+IA64_AR(fdr)
+
+IA64_AR(ccv)
+
+IA64_AR(unat)
+
+IA64_AR(fpsr)
+
+IA64_AR(itc)
+
+IA64_AR(pfs)
+IA64_AR(lc)
+IA64_AR(ec)
+
+/*
+ * Define accessors for control registers.
+ */
+
+#define IA64_CR(name)                                          \
+                                                               \
+static __inline uint64_t                                       \
+ia64_get_##name(void)                                          \
+{                                                              \
+       uint64_t result;                                        \
+       __asm __volatile("mov %0=cr." #name : "=r" (result));   \
+       return result;                                          \
+}                                                              \
+                                                               \
+static __inline void                                           \
+ia64_set_##name(uint64_t v)                                    \
+{                                                              \
+       __asm __volatile("mov cr." #name "=%0" :: "r" (v));     \
+}
+
+IA64_CR(dcr)
+IA64_CR(itm)
+IA64_CR(iva)
+
+IA64_CR(pta)
+
+IA64_CR(ipsr)
+IA64_CR(isr)
+
+IA64_CR(iip)
+IA64_CR(ifa)
+IA64_CR(itir)
+IA64_CR(iipa)
+IA64_CR(ifs)
+IA64_CR(iim)
+IA64_CR(iha)
+
+IA64_CR(lid)
+IA64_CR(ivr)
+IA64_CR(tpr)
+IA64_CR(eoi)
+IA64_CR(irr0)
+IA64_CR(irr1)
+IA64_CR(irr2)
+IA64_CR(irr3)
+IA64_CR(itv)
+IA64_CR(pmv)
+IA64_CR(cmcv)
+
+IA64_CR(lrr0)
+IA64_CR(lrr1)
+
+#define IA64_GR(name)                                          \
+                                                               \
+static __inline uint64_t                                       \
+ia64_get_##name(void)                                          \
+{                                                              \
+       uint64_t result;                                        \
+       __asm __volatile("mov %0=" #name : "=r" (result));      \
+       return result;                                          \
+}                                                              \
+                                                               \
+static __inline void                                           \
+ia64_set_##name(uint64_t v)                                    \
+{                                                              \
+       __asm __volatile("mov " #name "=%0" :: "r" (v));        \
+}
+
+IA64_GR(sp)
+IA64_GR(b0)
+IA64_GR(r13)   // tp
+
+
+/*
+ * Write a region register.
+ */
+static __inline void
+ia64_set_rr(uint64_t rrbase, uint64_t v)
+{
+       __asm __volatile("mov rr[%0]=%1;; srlz.d;;"
+                        :: "r"(rrbase), "r"(v) : "memory");
+}
+
+/*
+ * Read a region register.
+ */
+static __inline uint64_t
+ia64_get_rr(uint64_t rrbase)
+{
+       uint64_t v;
+       __asm __volatile("mov %1=rr[%0];;"
+                        : "=r" (v) : "r"(rrbase) : "memory");
+       return v;
+}
+
+
+/*
+ * Read a CPUID register.
+ */
+static __inline uint64_t
+ia64_get_cpuid(int i)
+{
+       uint64_t result;
+       __asm __volatile("mov %0=cpuid[%1]"
+                        : "=r" (result) : "r"(i));
+       return result;
+}
+
+
+struct trap_frame
+{
+       uint64_t        rsc;
+       uint64_t        ndirty;         /* number of dirty regs */
+       uint64_t        ssd;
+       uint64_t        iip;            /* interrupted ip */
+       uint64_t        ipsr;           /* interrupted psr */
+       uint64_t        ifs;            /* interruption func status register */
+
+       uint16_t        trap_num;       /* Trap num, index in trap_vec */
+       uint64_t        cfm;            /* current frame marker */
+       uint64_t        pfs;            /* previous function state ar64 */
+       uint64_t        bsp;            /* backing store pointer ar17 */
+       uint64_t        rnat;           /* rse nat collection ar19 */
+       uint64_t        csd;            /* comp and store data reg ar25 */
+       uint64_t        ccv;            /* comp and xchange val reg ar32 */
+       uint64_t        unat;           /* */
+       uint64_t        fpsr;           /* floating point state reg ar40 */
+       uint64_t        pr;             /* predicate regs 0-63 */
+
+       uint64_t        gp;             /* the gp pointer */
+       uint64_t        sp;             /* stack pointer */
+       uint64_t        tp;             /* thread pointer */
+
+       uint64_t        r2;             /* global reg 2 */
+       uint64_t        r3;
+       uint64_t        r8;
+       uint64_t        r9;
+       uint64_t        r10;
+       uint64_t        r11;
+       uint64_t        r14;
+       uint64_t        r15;
+       uint64_t        r16;
+       uint64_t        r17;
+       uint64_t        r18;
+       uint64_t        r19;
+       uint64_t        r20;
+       uint64_t        r21;
+       uint64_t        r22;
+       uint64_t        r23;
+       uint64_t        r24;
+       uint64_t        r25;
+       uint64_t        r26;
+       uint64_t        r27;
+       uint64_t        r28;
+       uint64_t        r29;
+       uint64_t        r30;
+       uint64_t        r31;
+
+       uint64_t        b0;
+       uint64_t        b6;
+       uint64_t        b7;
+
+       ia64_fpreg_t    f6;           /* floating point register 6 */
+       ia64_fpreg_t    f7;
+       ia64_fpreg_t    f8;
+       ia64_fpreg_t    f9;
+       ia64_fpreg_t    f10;
+       ia64_fpreg_t    f11;
+
+       uint64_t        ifa;            /* interruption faulting address */
+       uint64_t        isr;            /* interruption status register */
+       uint64_t        iim;            /* interruption immediate register */
+};
+
+typedef struct trap_frame trap_frame_t;
+
+
+#endif  /* __ASSEMBLY__ */
+
+/* Page access parameters. */
+#define PTE_P_SHIFT    0
+#define PTE_P          1
+
+#define PTE_MA_SHIFT   2
+#define PTE_MA_WB      0
+
+#define PTE_A_SHIFT    5
+#define PTE_A          1
+#define PTE_D_SHIFT    6
+#define PTE_D          1
+
+#define PTE_AR_SHIFT   9
+#define PTE_AR_R       0
+#define PTE_AR_RX      1
+#define PTE_AR_RW      2
+#define PTE_AR_RWX     3
+#define PTE_AR_R_RW    4
+#define PTE_AR_RX_RWX  5
+#define PTE_AR_RWX_RW  6
+/* privilege level */
+#define PTE_PL_SHIFT   7
+#define PTE_PL_KERN    0       /* used for kernel */
+/* page size */
+#define PTE_PS_4K      12
+#define PTE_PS_8K      13
+#define PTE_PS_16K     14
+#define PTE_PS_64K     16
+#define PTE_PS_256K    18
+#define PTE_PS_1M      20
+#define PTE_PS_4M      22
+#define PTE_PS_16M     24
+#define PTE_PS_64M     26
+#define PTE_PS_256M    28
+
+
+       /* Some offsets for ia64_pte_t. */
+#define PTE_OFF_P      0
+#define PTE_OFF_MA     3
+#define PTE_OFF_A      5
+#define PTE_OFF_D      6
+#define PTE_OFF_PL     7
+#define PTE_OFF_AR     9
+#define PTE_OFF_PPN    12
+#define PTE_OFF_ED     52
+
+#if !defined(_ASM) && !defined(__ASSEMBLY__)
+/*
+ * A short-format VHPT entry. Also matches the TLB insertion format.
+ */
+typedef struct
+{
+#if defined(BIG_ENDIAN)
+       uint64_t pte_ig :11;    /* bits 53..63 */
+       uint64_t pte_ed :1;     /* bits 52..52 */
+       uint64_t pte_rv2:2;     /* bits 50..51 */
+       uint64_t pte_ppn:38;    /* bits 12..49 */
+       uint64_t pte_ar :3;     /* bits 9..11 */
+       uint64_t pte_pl :2;     /* bits 7..8 */
+       uint64_t pte_d  :1;     /* bits 6..6 */
+       uint64_t pte_a  :1;     /* bits 5..5 */
+       uint64_t pte_ma :3;     /* bits 2..4 */
+       uint64_t pte_rv1:1;     /* bits 1..1 */
+       uint64_t pte_p  :1;     /* bits 0..0 */
+#else
+       uint64_t pte_p  :1;     /* bits 0..0 */
+       uint64_t pte_rv1:1;     /* bits 1..1 */
+       uint64_t pte_ma :3;     /* bits 2..4 */
+       uint64_t pte_a  :1;     /* bits 5..5 */
+       uint64_t pte_d  :1;     /* bits 6..6 */
+       uint64_t pte_pl :2;     /* bits 7..8 */
+       uint64_t pte_ar :3;     /* bits 9..11 */
+       uint64_t pte_ppn:38;    /* bits 12..49 */
+       uint64_t pte_rv2:2;     /* bits 50..51 */
+       uint64_t pte_ed :1;     /* bits 52..52 */
+       uint64_t pte_ig :11;    /* bits 53..63 */
+#endif
+} ia64_pte_t;
+
+
+/*
+ * A long-format VHPT entry.
+ */
+typedef struct
+{
+       uint64_t pte_p          :1;     /* bits 0..0 */
+       uint64_t pte_rv1        :1;     /* bits 1..1 */
+       uint64_t pte_ma         :3;     /* bits 2..4 */
+       uint64_t pte_a          :1;     /* bits 5..5 */
+       uint64_t pte_d          :1;     /* bits 6..6 */
+       uint64_t pte_pl         :2;     /* bits 7..8 */
+       uint64_t pte_ar         :3;     /* bits 9..11 */
+       uint64_t pte_ppn        :38;    /* bits 12..49 */
+       uint64_t pte_rv2        :2;     /* bits 50..51 */
+       uint64_t pte_ed         :1;     /* bits 52..52 */
+       uint64_t pte_ig         :11;    /* bits 53..63 */
+       uint64_t pte_rv3        :2;     /* bits 0..1 */
+       uint64_t pte_ps         :6;     /* bits 2..7 */
+       uint64_t pte_key        :24;    /* bits 8..31 */
+       uint64_t pte_rv4        :32;    /* bits 32..63 */
+       uint64_t pte_tag;               /* includes ti */
+       uint64_t pte_chain;             /* pa of collision chain */
+} ia64_lpte_t;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _IA64_CPU_H_ */
diff -r 092232fa1fbd extras/stubfw/include/ia64_fpu.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/include/ia64_fpu.h  Wed Nov 07 00:40:13 2007 +0100
@@ -0,0 +1,99 @@
+/*
+ * Done by Dietmar Hahn <dietmar.hahn@xxxxxxxxxxxxxxxxxxx>
+ * This code is mostly taken from FreeBSD.
+ *
+ ****************************************************************************
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _IA64_FPU_H_
+#define _IA64_FPU_H_
+
+#include "os.h"
+
+/*
+ * Floating point status register bits.
+ */
+#define IA64_FPSR_TRAP_VD      UL_CONST(0x0000000000000001)
+#define IA64_FPSR_TRAP_DD      UL_CONST(0x0000000000000002)
+#define IA64_FPSR_TRAP_ZD      UL_CONST(0x0000000000000004)
+#define IA64_FPSR_TRAP_OD      UL_CONST(0x0000000000000008)
+#define IA64_FPSR_TRAP_UD      UL_CONST(0x0000000000000010)
+#define IA64_FPSR_TRAP_ID      UL_CONST(0x0000000000000020)
+#define IA64_FPSR_SF(i,v)      ((v) << ((i)*13+6))
+
+#define IA64_SF_FTZ            UL_CONST(0x0001)
+#define IA64_SF_WRE            UL_CONST(0x0002)
+#define IA64_SF_PC             UL_CONST(0x000c)
+#define IA64_SF_PC_0           UL_CONST(0x0000)
+#define IA64_SF_PC_1           UL_CONST(0x0004)
+#define IA64_SF_PC_2           UL_CONST(0x0008)
+#define IA64_SF_PC_3           UL_CONST(0x000c)
+#define IA64_SF_RC             UL_CONST(0x0030)
+#define IA64_SF_RC_NEAREST     UL_CONST(0x0000)
+#define IA64_SF_RC_NEGINF      UL_CONST(0x0010)
+#define IA64_SF_RC_POSINF      UL_CONST(0x0020)
+#define IA64_SF_RC_TRUNC       UL_CONST(0x0030)
+#define IA64_SF_TD             UL_CONST(0x0040)
+#define IA64_SF_V              UL_CONST(0x0080)
+#define IA64_SF_D              UL_CONST(0x0100)
+#define IA64_SF_Z              UL_CONST(0x0200)
+#define IA64_SF_O              UL_CONST(0x0400)
+#define IA64_SF_U              UL_CONST(0x0800)
+#define IA64_SF_I              UL_CONST(0x1000)
+
+#define IA64_SF_DEFAULT        (IA64_SF_PC_3 | IA64_SF_RC_NEAREST)
+
+#define IA64_FPSR_DEFAULT      (IA64_FPSR_TRAP_VD                      \
+                                | IA64_FPSR_TRAP_DD                    \
+                                | IA64_FPSR_TRAP_ZD                    \
+                                | IA64_FPSR_TRAP_OD                    \
+                                | IA64_FPSR_TRAP_UD                    \
+                                | IA64_FPSR_TRAP_ID                    \
+                                | IA64_FPSR_SF(0, IA64_SF_DEFAULT)     \
+                                | IA64_FPSR_SF(1, (IA64_SF_DEFAULT     \
+                                                   | IA64_SF_TD        \
+                                                   | IA64_SF_WRE))     \
+                                | IA64_FPSR_SF(2, (IA64_SF_DEFAULT     \
+                                                   | IA64_SF_TD))      \
+                                | IA64_FPSR_SF(3, (IA64_SF_DEFAULT     \
+                                                   | IA64_SF_TD)))
+
+
+#ifndef __ASSEMBLY__
+
+       /* This is from sys/cdefs.h in FreeBSD */
+#define __aligned(x)    __attribute__((__aligned__(x)))
+
+       /* A single Floating Point register. */
+struct ia64_fpreg
+{
+       uint8_t fpr_bits[16];
+} __aligned(16);
+
+typedef struct ia64_fpreg ia64_fpreg_t;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _IA64_FPU_H_ */
diff -r 092232fa1fbd extras/stubfw/include/lib.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/include/lib.h       Wed Nov 14 03:17:18 2007 +0100
@@ -0,0 +1,121 @@
+/* -*-  Mode:C; c-basic-offset:4; tab-width:4 -*-
+ ****************************************************************************
+ * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
+ ****************************************************************************
+ *
+ *        File: lib.h
+ *      Author: Rolf Neugebauer (neugebar@xxxxxxxxxxxxx)
+ *     Changes: 
+ *              
+ *        Date: Aug 2003
+ * 
+ * Environment: Xen Minimal OS
+ * Description: Random useful library functions, contains some freebsd stuff
+ *
+ ****************************************************************************
+ * $Id: h-insert.h,v 1.4 2002/11/08 16:03:55 rn Exp $
+ ****************************************************************************
+ *
+ *-
+ * Copyright (c) 1991, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *      @(#)stdarg.h    8.1 (Berkeley) 6/10/93
+ * $FreeBSD: src/sys/i386/include/stdarg.h,v 1.10 1999/08/28 00:44:26 peter 
Exp $
+ */
+
+#ifndef _LIB_H_
+#define _LIB_H_
+
+#include <stdarg.h>
+#include <stddef.h>
+
+/* printing */
+#define _p(_x) ((void *)(unsigned long)(_x))
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
+int snprintf(char * buf, size_t size, const char *fmt, ...);
+int scnprintf(char * buf, size_t size, const char *fmt, ...);
+int vsprintf(char *buf, const char *fmt, va_list args);
+int sprintf(char * buf, const char *fmt, ...);
+int vsscanf(const char * buf, const char * fmt, va_list args);
+int sscanf(const char * buf, const char * fmt, ...);
+
+long simple_strtol(const char *cp,char **endp,unsigned int base);
+unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base);
+long long simple_strtoll(const char *cp,char **endp,unsigned int base);
+unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int 
base);
+
+
+void printk(const char *fmt, ...);
+void vprintf(const char *fmt, va_list args);
+void exit (void) __attribute__ ((noreturn));
+
+/* string and memory manipulation */
+int    memcmp(const void *cs, const void *ct, size_t count);
+void  *memcpy(void *dest, const void *src, size_t count);
+int    strncmp(const char *cs, const char *ct, size_t count);
+int    strcmp(const char *cs, const char *ct);
+char  *strcpy(char *dest, const char *src);
+char  *strncpy(char *dest, const char *src, size_t count);
+void  *memset(void *s,int c, size_t count);
+size_t strnlen(const char *s, size_t count);
+size_t strlen(const char *s);
+char  *strchr(const char *s, int c);
+char  *strstr(const char *s1, const char *s2);
+char * strcat(char * dest, const char * src);
+char  *strdup(const char *s);
+
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+struct kvec {
+    void *iov_base;
+    size_t iov_len;
+};
+
+#define ASSERT(x)                                              \
+do {                                                           \
+       if (!(x)) {                                                \
+               printk("ASSERTION FAILED: %s at %s:%d.\n",             \
+                          # x ,                                           \
+                          __FILE__,                                       \
+                          __LINE__);                                      \
+        BUG();                                                 \
+       }                                                          \
+} while(0)
+
+/* Consistency check as much as possible. */
+void sanity_check(void);
+
+void pstrcpy(char *buf, int buf_size, const char *str);
+
+#endif /* _LIB_H_ */
diff -r 092232fa1fbd extras/stubfw/include/os.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/include/os.h        Fri Nov 16 03:46:13 2007 +0100
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2007 - Dietmar Hahn <dietmar.hahn@xxxxxxxxxxxxxxxxxxx>
+ *
+ ****************************************************************************
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#if !defined(__OS_H__)
+#define __OS_H__
+
+#if !defined(__ASSEMBLY__)
+
+#include <stddef.h>
+#include "types.h"
+#include "xen/xen.h"
+#include "hypervisor.h"
+#include "ia64_cpu.h"
+#include "atomic.h"
+
+
+typedef uint64_t paddr_t;              /* Physical address. */
+typedef uint64_t caddr_t;              /* rr7/kernel memory address. */
+
+
+void do_exit(void);
+void arch_init(start_info_t *si);      /* in common.c */
+void arch_print_info(void);            /* in common.c */
+
+#define smp_processor_id() 0
+
+static inline uint64_t
+xchg8(uint64_t* ptr, uint64_t x)                                               
\
+{
+        uint64_t oldVal;
+        asm volatile ("xchg8 %0=[%1],%2" : "=r" (oldVal)
+                      : "r" (ptr), "r" (x) : "memory");
+        return oldVal;
+}
+#define xchg xchg8
+
+// Counts the number of 1-bits in x.
+#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+# define get_popcnt(x)         __builtin_popcountl(x)
+#else
+# define get_popcnt(x)                                 \
+  ({                                                   \
+       uint64_t num;                                   \
+       asm ("popcnt %0=%1" : "=r" (num) : "r" (x));    \
+       num;                                            \
+  })
+#endif
+
+/**
+ * __ffs - find first bit in word.
+ * @x: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static inline unsigned long
+__ffs (unsigned long x)
+{
+       unsigned long result;
+
+       result = get_popcnt((x-1) & ~x);
+       return result;
+}
+
+
+static inline void
+synch_clear_bit(int num, volatile void *addr)
+{
+       clear_bit(num, addr);
+}
+
+static inline void
+synch_set_bit(int num, volatile void *addr)
+{
+       set_bit(num, addr);
+}
+
+static inline int
+synch_test_bit(int nr, const volatile void *addr)
+{
+       return test_bit(nr, addr);
+}
+
+static inline int
+synch_test_and_set_bit(int num, volatile void * addr)
+{
+       return test_and_set_bit(num, addr);
+}
+
+
+#define synch_cmpxchg(ptr, old, new) \
+((__typeof__(*(ptr)))__synch_cmpxchg((ptr),\
+                                     (unsigned long)(old), \
+                                     (unsigned long)(new), \
+                                     sizeof(*(ptr))))
+
+static inline unsigned long
+__synch_cmpxchg(volatile void *ptr, uint64_t old, uint64_t new, int size)
+{
+       switch (size)
+       {
+               case 1:
+                       return ia64_cmpxchg_acq_8(ptr, old, new);
+               case 2:
+                       return ia64_cmpxchg_acq_16(ptr, old, new);
+               case 4:
+                       return ia64_cmpxchg_acq_32(ptr, old, new);
+               case 8:
+                       return ia64_cmpxchg_acq_64(ptr, old, new);
+       }
+       return ia64_cmpxchg_acq_64(ptr, old, new);
+}
+
+#if 0
+/*
+ * Force a proper event-channel callback from Xen after clearing the
+ * callback mask. We do this in a very simple manner, by making a call
+ * down into Xen. The pending flag will be checked by Xen on return.
+ */
+static inline void
+force_evtchn_callback(void)
+{
+       (void)HYPERVISOR_xen_version(0, NULL);
+}
+#endif
+
+extern shared_info_t *HYPERVISOR_shared_info;
+
+static inline int
+HYPERVISOR_shutdown(unsigned int reason)
+{
+       struct sched_shutdown sched_shutdown = {
+               .reason = reason
+       };
+
+       int rc = HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
+
+       return rc;
+}
+
+
+/*
+ * This code is from the originally os.h and should be put in a
+ * common header file!
+ */
+
+/* 
+ * The use of 'barrier' in the following reflects their use as local-lock
+ * operations. Reentrancy must be prevented (e.g., __cli()) /before/ following
+ * critical operations are executed. All critical operations must complete
+ * /before/ reentrancy is permitted (e.g., __sti()). Alpha architecture also
+ * includes these barriers, for example.
+ */
+
+#define __cli()                                                                
\
+do {                                                                   \
+       vcpu_info_t *_vcpu;                                             \
+       _vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()]; \
+       _vcpu->evtchn_upcall_mask = SWAP(1);                            \
+       barrier();                                                      \
+} while (0)
+
+#define __sti()                                                                
\
+do {                                                                   \
+       vcpu_info_t *_vcpu;                                             \
+       barrier();                                                      \
+       _vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()]; \
+       _vcpu->evtchn_upcall_mask = 0;                                  \
+       barrier(); /* unmask then check (avoid races) */                \
+       if (unlikely(SWAP(_vcpu->evtchn_upcall_pending)))               \
+               force_evtchn_callback();                                \
+} while (0)
+
+#define __save_flags(x)                                                        
\
+do {                                                                   \
+       vcpu_info_t *_vcpu;                                             \
+       _vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()]; \
+       (x) = SWAP(_vcpu->evtchn_upcall_mask);                          \
+} while (0)
+
+#define __restore_flags(x)                                             \
+do {                                                                   \
+       vcpu_info_t *_vcpu;                                             \
+       barrier();                                                      \
+       _vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()]; \
+       if ((_vcpu->evtchn_upcall_mask = (x)) == 0) {                   \
+               barrier(); /* unmask then check (avoid races) */        \
+               if ( unlikely(SWAP(_vcpu->evtchn_upcall_pending)) )     \
+                       force_evtchn_callback();                        \
+       }\
+} while (0)
+
+#define safe_halt()            ((void)0)
+
+#define __save_and_cli(x)                                              \
+do {                                                                   \
+       vcpu_info_t *_vcpu;                                             \
+       _vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()]; \
+       (x) = SWAP(_vcpu->evtchn_upcall_mask);                          \
+       _vcpu->evtchn_upcall_mask = SWAP(1);                            \
+       barrier();                                                      \
+} while (0)
+
+#define local_irq_save(x)      __save_and_cli(x)
+#define local_irq_restore(x)   __restore_flags(x)
+#define local_save_flags(x)    __save_flags(x)
+#define local_irq_disable()    __cli()
+#define local_irq_enable()     __sti()
+
+#define irqs_disabled()                        \
+       
SWAP(HYPERVISOR_shared_info->vcpu_info[smp_processor_id()].evtchn_upcall_mask)
+
+/* This is a barrier for the compiler only, NOT the processor! */
+#define barrier() __asm__ __volatile__("": : :"memory")
+
+#define mb()   ia64_mf()
+#define rmb()  mb()
+#define wmb()  mb()
+
+
+#define BUG()  \
+       { printk("mini-os BUG at %s:%d!\n", __FILE__, __LINE__); exit(); }
+
+#define PRINT_BV(_fmt, _params...)             \
+       if (bootverbose)                        \
+               printk(_fmt , ## _params)
+
+#endif /* !defined(__ASSEMBLY__) */
+
+#if defined(__ASSEMBLY__)
+
+#define UL_CONST(x)    x
+#define UL_TYPE(x)     x
+
+#else /* defined(__ASSEMBLY__) */
+
+#define UL_CONST(x)    x##UL
+#define UL_TYPE(x)     ((uint64_t)x)
+
+#endif /* defined(__ASSEMBLY__) */
+
+#endif /* !defined(__OS_H__) */
diff -r 092232fa1fbd extras/stubfw/include/types.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/include/types.h     Wed Nov 07 00:40:13 2007 +0100
@@ -0,0 +1,72 @@
+/* -*-  Mode:C; c-basic-offset:4; tab-width:4 -*-
+ ****************************************************************************
+ * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
+ ****************************************************************************
+ *
+ *        File: types.h
+ *      Author: Rolf Neugebauer (neugebar@xxxxxxxxxxxxx)
+ *     Changes: 
+ *              
+ *        Date: May 2003
+ * 
+ * Environment: Xen Minimal OS
+ * Description: a random collection of type definitions
+ *
+ ****************************************************************************
+ * $Id: h-insert.h,v 1.4 2002/11/08 16:03:55 rn Exp $
+ ****************************************************************************
+ */
+
+#ifndef _TYPES_H_
+#define _TYPES_H_
+
+typedef signed char         s8;
+typedef unsigned char       u8;
+typedef signed short        s16;
+typedef unsigned short      u16;
+typedef signed int          s32;
+typedef unsigned int        u32;
+#ifdef __i386__
+typedef signed long long    s64;
+typedef unsigned long long  u64;
+#elif defined(__x86_64__) || defined(__ia64__)
+typedef signed long         s64;
+typedef unsigned long       u64;
+#endif
+
+/* FreeBSD compat types */
+typedef unsigned char       u_char;
+typedef unsigned int        u_int;
+typedef unsigned long       u_long;
+#ifdef __i386__
+typedef long long           quad_t;
+typedef unsigned long long  u_quad_t;
+typedef unsigned int        uintptr_t;
+
+#if !defined(CONFIG_X86_PAE)
+typedef struct { unsigned long pte_low; } pte_t;
+#else
+typedef struct { unsigned long pte_low, pte_high; } pte_t;
+#endif /* CONFIG_X86_PAE */
+
+#elif defined(__x86_64__) || defined(__ia64__)
+typedef long                quad_t;
+typedef unsigned long       u_quad_t;
+typedef unsigned long       uintptr_t;
+
+typedef struct { unsigned long pte; } pte_t;
+#endif /* __i386__ || __x86_64__ */
+
+typedef  u8 uint8_t;
+typedef  s8 int8_t;
+typedef u16 uint16_t;
+typedef s16 int16_t;
+typedef u32 uint32_t;
+typedef s32 int32_t;
+typedef u64 uint64_t;
+typedef s64 int64_t;
+
+
+#define INT_MAX         ((int)(~0U>>1))
+#define UINT_MAX            (~0U)
+#endif /* _TYPES_H_ */
diff -r 092232fa1fbd extras/stubfw/include/xenbus.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/include/xenbus.h    Wed Nov 14 03:26:31 2007 +0100
@@ -0,0 +1,62 @@
+#ifndef XENBUS_H__
+#define XENBUS_H__
+
+typedef unsigned long xenbus_transaction_t;
+#define XBT_NIL ((xenbus_transaction_t)0)
+struct xenbus_req;
+
+/* Initialize the XenBus system. */
+void init_xenbus(void *interface, int evtchn);
+
+struct xenbus_req *xenbus_allocate_req (char *buf, int size);
+
+/* Read the value associated with a path.  Returns a malloc'd error
+   string on failure and sets *value to NULL.  On success, *value is
+   set to a malloc'd copy of the value. */
+const char *xenbus_read(struct xenbus_req *r, xenbus_transaction_t xbt, const 
char *path, char **value);
+
+const char *xenbus_watch_path(struct xenbus_req *r, xenbus_transaction_t xbt, 
const char *path);
+const char*xenbus_wait_for_value(struct xenbus_req *r,
+                                const char* path, const char* value);
+
+/* Associates a value with a path.  Returns a malloc'd error string on
+   failure. */
+const char *xenbus_write(struct xenbus_req *r, xenbus_transaction_t xbt, const 
char *path, const char *value);
+
+/* Removes the value associated with a path.  Returns a malloc'd error
+   string on failure. */
+const char *xenbus_rm(struct xenbus_req *r, xenbus_transaction_t xbt, const 
char *path);
+
+/* List the contents of a directory.  Returns a malloc'd error string
+   on failure and sets *contents to NULL.  On success, *contents is
+   set to a malloc'd array of pointers to malloc'd strings.  The array
+   is NULL terminated.  May block. */
+const char *xenbus_ls(struct xenbus_req *r, xenbus_transaction_t xbt,
+                     const char *dir, char **contents, int *contents_len);
+
+/* Reads permissions associated with a path.  Returns a malloc'd error
+   string on failure and sets *value to NULL.  On success, *value is
+   set to a malloc'd copy of the value. */
+const char *xenbus_get_perms(struct xenbus_req *r, xenbus_transaction_t xbt, 
const char *path, char **value);
+
+/* Sets the permissions associated with a path.  Returns a malloc'd
+   error string on failure. */
+const char *xenbus_set_perms(struct xenbus_req *r, xenbus_transaction_t xbt, 
const char *path, domid_t dom, char perm);
+
+/* Start a xenbus transaction.  Returns the transaction in xbt on
+   success or a malloc'd error string otherwise. */
+const char *xenbus_transaction_start(struct xenbus_req *r, 
xenbus_transaction_t *xbt);
+
+/* End a xenbus transaction.  Returns a malloc'd error string if it
+   fails.  abort says whether the transaction should be aborted.
+   Returns 1 in *retry iff the transaction should be retried. */
+const char *xenbus_transaction_end(struct xenbus_req *r, xenbus_transaction_t,
+                                  int abort, int *retry);
+
+/* Read path and parse it as an integer.  Returns -1 on error. */
+int xenbus_read_integer(struct xenbus_req *r, char *path);
+
+/* Send a debug message to xenbus.  Can block. */
+void xenbus_debug_msg(struct xenbus_req *r, const char *msg);
+
+#endif /* XENBUS_H__ */
diff -r 092232fa1fbd extras/stubfw/ioemu.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/ioemu.c     Wed Nov 21 16:00:38 2007 +0100
@@ -0,0 +1,397 @@
+#include "ioemu/vl.h"
+#include "console.h"
+#include "hypervisor.h"
+
+//#define DEBUG_IOPORT
+#define DEBUG_UNUSED_IOPORT
+//#define DEBUG_IOSAPIC
+
+void pstrcpy(char *buf, int buf_size, const char *str)
+{
+    int c;
+    char *q = buf;
+
+    if (buf_size <= 0)
+        return;
+
+    for(;;) {
+        c = *str++;
+        if (c == 0 || q >= buf + buf_size - 1)
+            break;
+        *q++ = c;
+    }
+    *q = '\0';
+}
+
+extern char end;
+static char *heap_ptr = &end;
+
+void *qemu_mallocz(size_t size)
+{
+  void *res;
+
+  /* Align.  */
+  size = (size + 0x0f) & ~0x0fUL;
+
+  res = heap_ptr;
+  heap_ptr += size;
+  memset (res, 0, size);
+
+  return res;
+}
+
+static void disp_ioport_map (void);
+
+void hw_error(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    printf("ioemu: hardware error: ");
+    vprintf(fmt, ap);
+    printf("\n");
+
+    disp_ioport_map ();
+    exit ();
+}
+
+struct ioport_map {
+  uint16_t base;
+  uint16_t end;
+  uint16_t off;
+};
+
+#define IOPORT_MAP_SIZE 16
+static int ioport_map_len;
+static int ioport_map_off;
+static struct ioport_map ioport_map[IOPORT_MAP_SIZE];
+
+static void disp_ioport_map (void)
+{
+    int i;
+
+    printf ("map_len=%d, map_off=%d\n", ioport_map_len, ioport_map_off);
+    for (i = 0; i < ioport_map_len; i++) {
+       printf ("%d: base=%4x end=%4x off=%d\n",
+               i, ioport_map[i].base, ioport_map[i].end, ioport_map[i].off);
+    }
+}
+    
+static int find_ioport(uint16_t port)
+{
+  int i;
+  for (i = 1; i < ioport_map_len; i++)
+    if (port >= ioport_map[i].base && port <= ioport_map[i].end)
+      return ioport_map[i].off + port - ioport_map[i].base;
+  return 0;
+}
+
+static int find_ioport_or_allocate(uint16_t port)
+{
+    int m = find_ioport (port);
+    if (m)
+       return m;
+    m = ioport_map_len - 1;
+    if (port == ioport_map[m].end + 1) {
+       /* Extend last one.  */
+       ioport_map[m].end++;
+       return ioport_map_off++;
+    }
+    if (ioport_map_len == IOPORT_MAP_SIZE)
+       hw_error ("ioport allocate: no more map");
+    m = ioport_map_len++;
+    ioport_map[m].base = port;
+    ioport_map[m].end = port;
+    ioport_map[m].off = ioport_map_off;
+    return ioport_map_off++;
+}
+
+#define MAX_IOPORTS 128
+static void *ioport_opaque_x[MAX_IOPORTS];
+static IOPortReadFunc *ioport_read_table_x[3][MAX_IOPORTS];
+static IOPortWriteFunc *ioport_write_table_x[3][MAX_IOPORTS];
+
+#ifdef DEBUG_UNUSED_IOPORT
+static int
+report_unused_port (uint32_t port)
+{
+  /* VGA.  */
+  if ((port & ~0x1f) == 0x3c0)
+    return 0;
+  /* Keyboard.  */
+  if ((port & ~0x4) == 0x60)
+    return 0;
+  /* PNP  */
+  if ((port & ~0x01) == 0x4d0)
+    return 0;
+  return 1;
+}
+#endif
+
+uint32_t default_ioport_readb(void *opaque, uint32_t address)
+{
+#ifdef DEBUG_UNUSED_IOPORT
+    if (report_unused_port (address))
+       printf("unused inb: port=0x%04x\n", address);
+#endif
+    return 0xff;
+}
+
+void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data)
+{
+#ifdef DEBUG_UNUSED_IOPORT
+    if (report_unused_port (address))
+       printf("unused outb: port=0x%04x data=0x%02x\n", address, data);
+#endif
+}
+
+/* default is to make two byte accesses */
+uint32_t default_ioport_readw(void *opaque, uint32_t address)
+{
+    uint32_t data;
+    data = cpu_inb(address);
+    data |= cpu_inb(address + 1) << 8;
+    return data;
+}
+
+void default_ioport_writew(void *opaque, uint32_t address, uint32_t data)
+{
+  cpu_outb(address, data & 0xff);
+  cpu_outb(address, (data >> 8) & 0xff);
+}
+
+uint32_t default_ioport_readl(void *opaque, uint32_t address)
+{
+#ifdef DEBUG_UNUSED_IOPORT
+    if (report_unused_port (address))
+       printf("unused inl: port=0x%04x\n", address);
+#endif
+    return 0xffffffff;
+}
+
+void default_ioport_writel(void *opaque, uint32_t address, uint32_t data)
+{
+#ifdef DEBUG_UNUSED_IOPORT
+    if (report_unused_port (address))
+       printf("unused outl: port=0x%04x data=0x%02x\n", address, data);
+#endif
+}
+
+void init_ioports(void)
+{
+  int i = 0;
+
+  for (i = 0; i < MAX_IOPORTS; i++) {
+    ioport_read_table_x[0][i] = default_ioport_readb;
+    ioport_write_table_x[0][i] = default_ioport_writeb;
+    ioport_read_table_x[1][i] = default_ioport_readw;
+    ioport_write_table_x[1][i] = default_ioport_writew;
+    ioport_read_table_x[2][i] = default_ioport_readl;
+    ioport_write_table_x[2][i] = default_ioport_writel;
+  }
+  ioport_map_len = 1;
+  ioport_map_off = 1;
+}
+
+/* size is the word size in byte */
+int register_ioport_read(int start, int length, int size,
+                         IOPortReadFunc *func, void *opaque)
+{
+    int i, bsize;
+
+    if (size == 1) {
+        bsize = 0;
+    } else if (size == 2) {
+        bsize = 1;
+    } else if (size == 4) {
+        bsize = 2;
+    } else {
+        hw_error("register_ioport_read: invalid size");
+        return -1;
+    }
+    for(i = start; i < start + length; i += size) {
+       int m = find_ioport_or_allocate (i);
+        ioport_read_table_x[bsize][m] = func;
+        if (ioport_opaque_x[m] != NULL && ioport_opaque_x[m] != opaque)
+            hw_error("register_ioport_read: invalid opaque");
+        ioport_opaque_x[m] = opaque;
+    }
+    return 0;
+}
+
+/* size is the word size in byte */
+int register_ioport_write(int start, int length, int size,
+                          IOPortWriteFunc *func, void *opaque)
+{
+    int i, bsize;
+
+#if 0
+    printf ("register_ioport_write: start=%3x len=%3x size=%d opq=%lx\n",
+           start, length, size, opaque);
+#endif
+    if (size == 1) {
+        bsize = 0;
+    } else if (size == 2) {
+        bsize = 1;
+    } else if (size == 4) {
+        bsize = 2;
+    } else {
+        hw_error("register_ioport_write: invalid size");
+        return -1;
+    }
+    for(i = start; i < start + length; i += size) {
+       int m = find_ioport_or_allocate (i);
+        ioport_write_table_x[bsize][m] = func;
+        if (ioport_opaque_x[m] != NULL && ioport_opaque_x[m] != opaque)
+            hw_error("register_ioport_write: invalid opaque");
+        ioport_opaque_x[m] = opaque;
+    }
+    return 0;
+}
+
+#if 0
+void isa_unassign_ioport(int start, int length)
+{
+    int i;
+
+    for(i = start; i < start + length; i++) {
+        ioport_read_table[0][i] = default_ioport_readb;
+        ioport_read_table[1][i] = default_ioport_readw;
+        ioport_read_table[2][i] = default_ioport_readl;
+
+        ioport_write_table[0][i] = default_ioport_writeb;
+        ioport_write_table[1][i] = default_ioport_writew;
+        ioport_write_table[2][i] = default_ioport_writel;
+    }
+}
+#endif
+
+/***********************************************************/
+
+void cpu_outb(int addr, int val)
+{
+    int m = find_ioport (addr);
+#ifdef DEBUG_IOPORT
+    printf("outb: %04x %02x\n", addr, val);
+#endif
+    ioport_write_table_x[0][m](ioport_opaque_x[m], addr, val);
+}
+
+void cpu_outw(int addr, int val)
+{
+    int m = find_ioport (addr);
+#ifdef DEBUG_IOPORT
+    printf("outw: %04x %04x\n", addr, val);
+#endif
+    ioport_write_table_x[1][m](ioport_opaque_x[m], addr, val);
+}
+
+void cpu_outl(int addr, int val)
+{
+    int m = find_ioport (addr);
+#ifdef DEBUG_IOPORT
+    printf("outl: %04x %08x\n", addr, val);
+#endif
+    ioport_write_table_x[2][m](ioport_opaque_x[m], addr, val);
+}
+
+int cpu_inb(int addr)
+{
+    int m = find_ioport (addr);
+    int val;
+    val = ioport_read_table_x[0][m](ioport_opaque_x[m], addr);
+#ifdef DEBUG_IOPORT
+    printf("inb : %04x %02x\n", addr, val);
+#endif
+    return val;
+}
+
+int cpu_inw(int addr)
+{
+    int m = find_ioport (addr);
+    int val;
+    val = ioport_read_table_x[1][m](ioport_opaque_x[m], addr);
+#ifdef DEBUG_IOPORT
+    printf("inw : %04x %04x\n", addr, val);
+#endif
+    return val;
+}
+
+int cpu_inl(int addr)
+{
+    int m = find_ioport (addr);
+    int val;
+    val = ioport_read_table_x[2][m](ioport_opaque_x[m], addr);
+#ifdef DEBUG_IOPORT
+    printf("inl : %04x %08x\n", addr, val);
+#endif
+    return val;
+}
+
+#define __ia64_fc(addr)        asm volatile ("fc %0" :: "r"(addr) : "memory")
+#define ia64_sync_i()  asm volatile (";; sync.i" ::: "memory")
+#define ia64_srlz_i()  asm volatile (";; srlz.i ;;" ::: "memory")
+
+/* IA64 has seperate I/D cache, with coherence maintained by DMA controller.
+ * So to emulate right behavior that guest OS is assumed, we need to flush
+ * I/D cache here.
+ */
+static void sync_icache(unsigned long address, int len)
+{
+    int l;
+
+    for(l = 0; l < (len + 32); l += 32)
+        __ia64_fc(address + l);
+
+    ia64_sync_i();
+    ia64_srlz_i();
+}
+
+void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
+                            int len, int is_write)
+{
+  if (is_write) {
+    memcpy ((void *)addr, buf, len);
+    sync_icache (addr, len);
+  }
+  else
+    memcpy (buf, (void *)addr, len);
+}
+
+BlockDriverState *bs_table[MAX_DISKS + 1];
+
+static uint8_t irq_level[48];
+static void iosapic_set_irq(void *opaque, int irq, int level)
+{
+    int res;
+
+    if (level == irq_level[irq])
+       return;
+
+    irq_level[irq] = level;
+
+#if defined(DEBUG_IOSAPIC)
+    printf("iospaic_set_irq: irq=%d level=%d\n", irq, level);
+#endif
+    if (irq < 16)
+       res = HYPERVISOR_hvm_set_isa_irq_level(DOMID_SELF, irq, level);
+    else {
+       int pci_irq = irq - 16;
+       res = HYPERVISOR_hvm_set_pci_intx_level
+           (DOMID_SELF, 0, 0, (pci_irq >> 2), (pci_irq & 3), level);
+    }
+    if (res != 0)
+       printk ("ioemu: can set irq level (irq=%d, err=%d)\n", irq, res);
+}
+
+qemu_irq *
+init_iosapic (void)
+{
+  qemu_irq *res;
+
+  res = qemu_allocate_irqs (iosapic_set_irq, NULL, 48);
+
+  return res;
+}
+
+
diff -r 092232fa1fbd extras/stubfw/ioemu/block.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/ioemu/block.c       Sat Nov 17 05:12:18 2007 +0100
@@ -0,0 +1,1386 @@
+/*
+ * QEMU System Emulator block driver
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+#include "block_int.h"
+
+#ifdef _BSD
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/queue.h>
+#include <sys/disk.h>
+#endif
+
+
+#ifndef IOEMU
+typedef struct BlockDriverAIOCBSync {
+    BlockDriverAIOCB common;
+    QEMUBH *bh;
+    int ret;
+} BlockDriverAIOCBSync;
+#else
+typedef struct BlockDriverAIOCBSync {
+    int ret;
+} BlockDriverAIOCBSync;
+
+#endif
+
+static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,
+        int64_t sector_num, uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
+static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs,
+        int64_t sector_num, const uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
+
+static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb);
+#ifndef IOEMU
+static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
+                        uint8_t *buf, int nb_sectors);
+static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
+                         const uint8_t *buf, int nb_sectors);
+#endif
+
+static BlockDriverState *bdrv_first;
+//static BlockDriver *first_drv;
+
+#ifndef IOEMU
+int path_is_absolute(const char *path)
+{
+    const char *p;
+#ifdef _WIN32
+    /* specific case for names like: "\\.\d:" */
+    if (*path == '/' || *path == '\\')
+        return 1;
+#endif
+    p = strchr(path, ':');
+    if (p)
+        p++;
+    else
+        p = path;
+#ifdef _WIN32
+    return (*p == '/' || *p == '\\');
+#else
+    return (*p == '/');
+#endif
+}
+
+/* if filename is absolute, just copy it to dest. Otherwise, build a
+   path to it by considering it is relative to base_path. URL are
+   supported. */
+void path_combine(char *dest, int dest_size,
+                  const char *base_path,
+                  const char *filename)
+{
+    const char *p, *p1;
+    int len;
+
+    if (dest_size <= 0)
+        return;
+    if (path_is_absolute(filename)) {
+        pstrcpy(dest, dest_size, filename);
+    } else {
+        p = strchr(base_path, ':');
+        if (p)
+            p++;
+        else
+            p = base_path;
+        p1 = strrchr(base_path, '/');
+#ifdef _WIN32
+        {
+            const char *p2;
+            p2 = strrchr(base_path, '\\');
+            if (!p1 || p2 > p1)
+                p1 = p2;
+        }
+#endif
+        if (p1)
+            p1++;
+        else
+            p1 = base_path;
+        if (p1 > p)
+            p = p1;
+        len = p - base_path;
+        if (len > dest_size - 1)
+            len = dest_size - 1;
+        memcpy(dest, base_path, len);
+        dest[len] = '\0';
+        pstrcat(dest, dest_size, filename);
+    }
+}
+#endif
+
+void bdrv_register(BlockDriver *bdrv)
+{
+    if (!bdrv->bdrv_aio_read) {
+        /* add AIO emulation layer */
+        bdrv->bdrv_aio_read = bdrv_aio_read_em;
+        bdrv->bdrv_aio_write = bdrv_aio_write_em;
+        bdrv->bdrv_aio_cancel = bdrv_aio_cancel_em;
+        bdrv->aiocb_size = sizeof(BlockDriverAIOCBSync);
+    }
+#ifndef IOEMU
+    else if (!bdrv->bdrv_read && !bdrv->bdrv_pread) {
+        /* add synchronous IO emulation layer */
+        bdrv->bdrv_read = bdrv_read_em;
+        bdrv->bdrv_write = bdrv_write_em;
+    }
+    bdrv->next = first_drv;
+    first_drv = bdrv;
+#endif
+}
+
+/* create a new block device (by default it is empty) */
+BlockDriverState *bdrv_new(const char *device_name)
+{
+    BlockDriverState **pbs, *bs;
+
+    bs = qemu_mallocz(sizeof(BlockDriverState));
+    if(!bs)
+        return NULL;
+    pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
+    if (device_name[0] != '\0') {
+        /* insert at the end */
+        pbs = &bdrv_first;
+        while (*pbs != NULL)
+            pbs = &(*pbs)->next;
+        *pbs = bs;
+    }
+    return bs;
+}
+
+#ifndef IOEMU
+BlockDriver *bdrv_find_format(const char *format_name)
+{
+    BlockDriver *drv1;
+    for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
+        if (!strcmp(drv1->format_name, format_name))
+            return drv1;
+    }
+    return NULL;
+}
+
+int bdrv_create(BlockDriver *drv,
+                const char *filename, int64_t size_in_sectors,
+                const char *backing_file, int flags)
+{
+    if (!drv->bdrv_create)
+        return -ENOTSUP;
+    return drv->bdrv_create(filename, size_in_sectors, backing_file, flags);
+}
+
+#ifdef _WIN32
+void get_tmp_filename(char *filename, int size)
+{
+    char temp_dir[MAX_PATH];
+
+    GetTempPath(MAX_PATH, temp_dir);
+    GetTempFileName(temp_dir, "qem", 0, filename);
+}
+#else
+void get_tmp_filename(char *filename, int size)
+{
+    int fd;
+    /* XXX: race condition possible */
+    pstrcpy(filename, size, "/tmp/vl.XXXXXX");
+    fd = mkstemp(filename);
+    close(fd);
+}
+#endif
+
+#ifdef _WIN32
+static int is_windows_drive_prefix(const char *filename)
+{
+    return (((filename[0] >= 'a' && filename[0] <= 'z') ||
+             (filename[0] >= 'A' && filename[0] <= 'Z')) &&
+            filename[1] == ':');
+}
+
+static int is_windows_drive(const char *filename)
+{
+    if (is_windows_drive_prefix(filename) &&
+        filename[2] == '\0')
+        return 1;
+    if (strstart(filename, "\\\\.\\", NULL) ||
+        strstart(filename, "//./", NULL))
+        return 1;
+    return 0;
+}
+#endif
+
+static BlockDriver *find_protocol(const char *filename)
+{
+    BlockDriver *drv1;
+    char protocol[128];
+    int len;
+    const char *p;
+
+#ifdef _WIN32
+    if (is_windows_drive(filename) ||
+        is_windows_drive_prefix(filename))
+        return &bdrv_raw;
+#endif
+    p = strchr(filename, ':');
+    if (!p)
+        return &bdrv_raw;
+    len = p - filename;
+    if (len > sizeof(protocol) - 1)
+        len = sizeof(protocol) - 1;
+    memcpy(protocol, filename, len);
+    protocol[len] = '\0';
+    for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
+        if (drv1->protocol_name &&
+            !strcmp(drv1->protocol_name, protocol))
+            return drv1;
+    }
+    return NULL;
+}
+
+/* XXX: force raw format if block or character device ? It would
+   simplify the BSD case */
+static BlockDriver *find_image_format(const char *filename)
+{
+    int ret, score, score_max;
+    BlockDriver *drv1, *drv;
+    uint8_t buf[2048];
+    BlockDriverState *bs;
+
+    /* detect host devices. By convention, /dev/cdrom[N] is always
+       recognized as a host CDROM */
+    if (strstart(filename, "/dev/cdrom", NULL))
+        return &bdrv_host_device;
+#ifdef _WIN32
+    if (is_windows_drive(filename))
+        return &bdrv_host_device;
+#else
+    {
+        struct stat st;
+        if (stat(filename, &st) >= 0 &&
+            (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) {
+            return &bdrv_host_device;
+        }
+    }
+#endif
+
+    drv = find_protocol(filename);
+    /* no need to test disk image formats for vvfat */
+    if (drv == &bdrv_vvfat)
+        return drv;
+
+    ret = bdrv_file_open(&bs, filename, BDRV_O_RDONLY);
+    if (ret < 0)
+        return NULL;
+    ret = bdrv_pread(bs, 0, buf, sizeof(buf));
+    bdrv_delete(bs);
+    if (ret < 0) {
+        return NULL;
+    }
+
+    score_max = 0;
+    for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
+        if (drv1->bdrv_probe) {
+            score = drv1->bdrv_probe(buf, ret, filename);
+            if (score > score_max) {
+                score_max = score;
+                drv = drv1;
+            }
+        }
+    }
+    return drv;
+}
+
+int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
+{
+    BlockDriverState *bs;
+    int ret;
+
+    bs = bdrv_new("");
+    if (!bs)
+        return -ENOMEM;
+    ret = bdrv_open2(bs, filename, flags | BDRV_O_FILE, NULL);
+    if (ret < 0) {
+        bdrv_delete(bs);
+        return ret;
+    }
+    *pbs = bs;
+    return 0;
+}
+
+int bdrv_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    return bdrv_open2(bs, filename, flags, NULL);
+}
+
+int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
+               BlockDriver *drv)
+{
+    int ret, open_flags;
+    char tmp_filename[PATH_MAX];
+    char backing_filename[PATH_MAX];
+
+    bs->read_only = 0;
+    bs->is_temporary = 0;
+    bs->encrypted = 0;
+
+    if (flags & BDRV_O_SNAPSHOT) {
+        BlockDriverState *bs1;
+        int64_t total_size;
+
+        /* if snapshot, we create a temporary backing file and open it
+           instead of opening 'filename' directly */
+
+        /* if there is a backing file, use it */
+        bs1 = bdrv_new("");
+        if (!bs1) {
+            return -ENOMEM;
+        }
+        if (bdrv_open(bs1, filename, 0) < 0) {
+            bdrv_delete(bs1);
+            return -1;
+        }
+        total_size = bdrv_getlength(bs1) >> SECTOR_BITS;
+        bdrv_delete(bs1);
+
+        get_tmp_filename(tmp_filename, sizeof(tmp_filename));
+        realpath(filename, backing_filename);
+        if (bdrv_create(&bdrv_qcow2, tmp_filename,
+                        total_size, backing_filename, 0) < 0) {
+            return -1;
+        }
+        filename = tmp_filename;
+        bs->is_temporary = 1;
+    }
+
+    pstrcpy(bs->filename, sizeof(bs->filename), filename);
+    if (flags & BDRV_O_FILE) {
+        drv = find_protocol(filename);
+        if (!drv)
+            return -ENOENT;
+    } else {
+        if (!drv) {
+            drv = find_image_format(filename);
+            if (!drv)
+                return -1;
+        }
+    }
+    bs->drv = drv;
+    bs->opaque = qemu_mallocz(drv->instance_size);
+    if (bs->opaque == NULL && drv->instance_size > 0)
+        return -1;
+    /* Note: for compatibility, we open disk image files as RDWR, and
+       RDONLY as fallback */
+    if (!(flags & BDRV_O_FILE))
+        open_flags = BDRV_O_RDWR;
+    else
+        open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT);
+    ret = drv->bdrv_open(bs, filename, open_flags);
+    if (ret == -EACCES && !(flags & BDRV_O_FILE)) {
+        ret = drv->bdrv_open(bs, filename, BDRV_O_RDONLY);
+        bs->read_only = 1;
+    }
+    if (ret < 0) {
+        qemu_free(bs->opaque);
+        bs->opaque = NULL;
+        bs->drv = NULL;
+        return ret;
+    }
+    if (drv->bdrv_getlength) {
+        bs->total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
+    }
+#ifndef _WIN32
+    if (bs->is_temporary) {
+        unlink(filename);
+    }
+#endif
+    if (bs->backing_file[0] != '\0') {
+        /* if there is a backing file, use it */
+        bs->backing_hd = bdrv_new("");
+        if (!bs->backing_hd) {
+        fail:
+            bdrv_close(bs);
+            return -ENOMEM;
+        }
+        path_combine(backing_filename, sizeof(backing_filename),
+                     filename, bs->backing_file);
+        if (bdrv_open(bs->backing_hd, backing_filename, 0) < 0)
+            goto fail;
+    }
+
+    /* call the change callback */
+    bs->media_changed = 1;
+    if (bs->change_cb)
+        bs->change_cb(bs->change_opaque);
+
+    return 0;
+}
+#endif
+
+void bdrv_close(BlockDriverState *bs)
+{
+    if (bs->drv) {
+#ifndef IOEMU
+        if (bs->backing_hd)
+            bdrv_delete(bs->backing_hd);
+        bs->drv->bdrv_close(bs);
+        qemu_free(bs->opaque);
+#ifdef _WIN32
+        if (bs->is_temporary) {
+            unlink(bs->filename);
+        }
+#endif
+        bs->opaque = NULL;
+#endif
+        bs->drv = NULL;
+
+        /* call the change callback */
+        bs->media_changed = 1;
+        if (bs->change_cb)
+            bs->change_cb(bs->change_opaque);
+    }
+}
+
+#ifndef IOEMU
+void bdrv_delete(BlockDriverState *bs)
+{
+    /* XXX: remove the driver list */
+    bdrv_close(bs);
+    qemu_free(bs);
+}
+
+/* commit COW file into the raw image */
+int bdrv_commit(BlockDriverState *bs)
+{
+    BlockDriver *drv = bs->drv;
+    int64_t i, total_sectors;
+    int n, j;
+    unsigned char sector[512];
+
+    if (!drv)
+        return -ENOMEDIUM;
+
+    if (bs->read_only) {
+       return -EACCES;
+    }
+
+    if (!bs->backing_hd) {
+       return -ENOTSUP;
+    }
+
+    total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
+    for (i = 0; i < total_sectors;) {
+        if (drv->bdrv_is_allocated(bs, i, 65536, &n)) {
+            for(j = 0; j < n; j++) {
+                if (bdrv_read(bs, i, sector, 1) != 0) {
+                    return -EIO;
+                }
+
+                if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) {
+                    return -EIO;
+                }
+                i++;
+           }
+       } else {
+            i += n;
+        }
+    }
+
+    if (drv->bdrv_make_empty)
+       return drv->bdrv_make_empty(bs);
+
+    return 0;
+}
+#endif
+
+/* return < 0 if error. See bdrv_write() for the return codes */
+int bdrv_read(BlockDriverState *bs, int64_t sector_num,
+              uint8_t *buf, int nb_sectors)
+{
+    BlockDriver *drv = bs->drv;
+
+    if (!drv)
+        return -ENOMEDIUM;
+
+#ifdef IOEMU
+    if ((unsigned long)buf & SECTOR_MASK) {
+      printf ("bdrv_read: bad buf (%p) from %p\n",
+             buf, __builtin_return_address (0));
+    }
+#endif
+
+    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
+            memcpy(buf, bs->boot_sector_data, 512);
+        sector_num++;
+        nb_sectors--;
+        buf += 512;
+        if (nb_sectors == 0)
+            return 0;
+    }
+    if (drv->bdrv_pread) {
+        int ret, len;
+        len = nb_sectors * 512;
+        ret = drv->bdrv_pread(bs, sector_num * 512, buf, len);
+        if (ret < 0)
+            return ret;
+        else if (ret != len)
+            return -EINVAL;
+        else
+            return 0;
+    } else {
+        return drv->bdrv_read(bs, sector_num, buf, nb_sectors);
+    }
+}
+
+/* Return < 0 if error. Important errors are:
+  -EIO         generic I/O error (may happen for all errors)
+  -ENOMEDIUM   No media inserted.
+  -EINVAL      Invalid sector number or nb_sectors
+  -EACCES      Trying to write a read-only device
+*/
+int bdrv_write(BlockDriverState *bs, int64_t sector_num,
+               const uint8_t *buf, int nb_sectors)
+{
+    BlockDriver *drv = bs->drv;
+    if (!bs->drv)
+        return -ENOMEDIUM;
+    if (bs->read_only)
+        return -EACCES;
+    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
+        memcpy(bs->boot_sector_data, buf, 512);
+    }
+    if (drv->bdrv_pwrite) {
+        int ret, len;
+        len = nb_sectors * 512;
+        ret = drv->bdrv_pwrite(bs, sector_num * 512, buf, len);
+        if (ret < 0)
+            return ret;
+        else if (ret != len)
+            return -EIO;
+        else
+            return 0;
+    } else {
+        return drv->bdrv_write(bs, sector_num, buf, nb_sectors);
+    }
+}
+
+#ifndef IOEMU
+static int bdrv_pread_em(BlockDriverState *bs, int64_t offset,
+                         uint8_t *buf, int count1)
+{
+    uint8_t tmp_buf[SECTOR_SIZE];
+    int len, nb_sectors, count;
+    int64_t sector_num;
+
+    count = count1;
+    /* first read to align to sector start */
+    len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1);
+    if (len > count)
+        len = count;
+    sector_num = offset >> SECTOR_BITS;
+    if (len > 0) {
+        if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
+            return -EIO;
+        memcpy(buf, tmp_buf + (offset & (SECTOR_SIZE - 1)), len);
+        count -= len;
+        if (count == 0)
+            return count1;
+        sector_num++;
+        buf += len;
+    }
+
+    /* read the sectors "in place" */
+    nb_sectors = count >> SECTOR_BITS;
+    if (nb_sectors > 0) {
+        if (bdrv_read(bs, sector_num, buf, nb_sectors) < 0)
+            return -EIO;
+        sector_num += nb_sectors;
+        len = nb_sectors << SECTOR_BITS;
+        buf += len;
+        count -= len;
+    }
+
+    /* add data from the last sector */
+    if (count > 0) {
+        if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
+            return -EIO;
+        memcpy(buf, tmp_buf, count);
+    }
+    return count1;
+}
+
+static int bdrv_pwrite_em(BlockDriverState *bs, int64_t offset,
+                          const uint8_t *buf, int count1)
+{
+    uint8_t tmp_buf[SECTOR_SIZE];
+    int len, nb_sectors, count;
+    int64_t sector_num;
+
+    count = count1;
+    /* first write to align to sector start */
+    len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1);
+    if (len > count)
+        len = count;
+    sector_num = offset >> SECTOR_BITS;
+    if (len > 0) {
+        if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
+            return -EIO;
+        memcpy(tmp_buf + (offset & (SECTOR_SIZE - 1)), buf, len);
+        if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)
+            return -EIO;
+        count -= len;
+        if (count == 0)
+            return count1;
+        sector_num++;
+        buf += len;
+    }
+
+    /* write the sectors "in place" */
+    nb_sectors = count >> SECTOR_BITS;
+    if (nb_sectors > 0) {
+        if (bdrv_write(bs, sector_num, buf, nb_sectors) < 0)
+            return -EIO;
+        sector_num += nb_sectors;
+        len = nb_sectors << SECTOR_BITS;
+        buf += len;
+        count -= len;
+    }
+
+    /* add data from the last sector */
+    if (count > 0) {
+        if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
+            return -EIO;
+        memcpy(tmp_buf, buf, count);
+        if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)
+            return -EIO;
+    }
+    return count1;
+}
+
+/**
+ * Read with byte offsets (needed only for file protocols)
+ */
+int bdrv_pread(BlockDriverState *bs, int64_t offset,
+               void *buf1, int count1)
+{
+    BlockDriver *drv = bs->drv;
+
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_pread)
+        return bdrv_pread_em(bs, offset, buf1, count1);
+    return drv->bdrv_pread(bs, offset, buf1, count1);
+}
+
+/**
+ * Write with byte offsets (needed only for file protocols)
+ */
+int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
+                const void *buf1, int count1)
+{
+    BlockDriver *drv = bs->drv;
+
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_pwrite)
+        return bdrv_pwrite_em(bs, offset, buf1, count1);
+    return drv->bdrv_pwrite(bs, offset, buf1, count1);
+}
+
+/**
+ * Truncate file to 'offset' bytes (needed only for file protocols)
+ */
+int bdrv_truncate(BlockDriverState *bs, int64_t offset)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_truncate)
+        return -ENOTSUP;
+    return drv->bdrv_truncate(bs, offset);
+}
+#endif
+
+/**
+ * Length of a file in bytes. Return < 0 if error or unknown.
+ */
+int64_t bdrv_getlength(BlockDriverState *bs)
+{
+    BlockDriver *drv = bs->drv;
+    
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_getlength) {
+        /* legacy mode */
+        return bs->total_sectors * SECTOR_SIZE;
+    }
+    return drv->bdrv_getlength(bs);
+}
+
+/* return 0 as number of sectors if no device present or error */
+void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
+{
+    int64_t length;
+    length = bdrv_getlength(bs);
+    if (length < 0)
+        length = 0;
+    else
+        length = length >> SECTOR_BITS;
+    *nb_sectors_ptr = length;
+}
+
+/* force a given boot sector. */
+void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size)
+{
+    bs->boot_sector_enabled = 1;
+    if (size > 512)
+        size = 512;
+    memcpy(bs->boot_sector_data, data, size);
+    memset(bs->boot_sector_data + size, 0, 512 - size);
+}
+
+void bdrv_set_geometry_hint(BlockDriverState *bs,
+                            int cyls, int heads, int secs)
+{
+    bs->cyls = cyls;
+    bs->heads = heads;
+    bs->secs = secs;
+}
+
+void bdrv_set_type_hint(BlockDriverState *bs, int type)
+{
+    bs->type = type;
+    bs->removable = ((type == BDRV_TYPE_CDROM ||
+                      type == BDRV_TYPE_FLOPPY));
+}
+
+void bdrv_set_translation_hint(BlockDriverState *bs, int translation)
+{
+    bs->translation = translation;
+}
+
+void bdrv_get_geometry_hint(BlockDriverState *bs,
+                            int *pcyls, int *pheads, int *psecs)
+{
+    *pcyls = bs->cyls;
+    *pheads = bs->heads;
+    *psecs = bs->secs;
+}
+
+int bdrv_get_type_hint(BlockDriverState *bs)
+{
+    return bs->type;
+}
+
+int bdrv_get_translation_hint(BlockDriverState *bs)
+{
+    return bs->translation;
+}
+
+int bdrv_is_removable(BlockDriverState *bs)
+{
+    return bs->removable;
+}
+
+int bdrv_is_read_only(BlockDriverState *bs)
+{
+    return bs->read_only;
+}
+
+/* XXX: no longer used */
+void bdrv_set_change_cb(BlockDriverState *bs,
+                        void (*change_cb)(void *opaque), void *opaque)
+{
+    bs->change_cb = change_cb;
+    bs->change_opaque = opaque;
+}
+
+#ifndef IOEMU
+int bdrv_is_encrypted(BlockDriverState *bs)
+{
+    if (bs->backing_hd && bs->backing_hd->encrypted)
+        return 1;
+    return bs->encrypted;
+}
+
+int bdrv_set_key(BlockDriverState *bs, const char *key)
+{
+    int ret;
+    if (bs->backing_hd && bs->backing_hd->encrypted) {
+        ret = bdrv_set_key(bs->backing_hd, key);
+        if (ret < 0)
+            return ret;
+        if (!bs->encrypted)
+            return 0;
+    }
+    if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key)
+        return -1;
+    return bs->drv->bdrv_set_key(bs, key);
+}
+
+void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size)
+{
+    if (!bs->drv) {
+        buf[0] = '\0';
+    } else {
+        pstrcpy(buf, buf_size, bs->drv->format_name);
+    }
+}
+
+void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
+                         void *opaque)
+{
+    BlockDriver *drv;
+
+    for (drv = first_drv; drv != NULL; drv = drv->next) {
+        it(opaque, drv->format_name);
+    }
+}
+
+BlockDriverState *bdrv_find(const char *name)
+{
+    BlockDriverState *bs;
+
+    for (bs = bdrv_first; bs != NULL; bs = bs->next) {
+        if (!strcmp(name, bs->device_name))
+            return bs;
+    }
+    return NULL;
+}
+
+void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque)
+{
+    BlockDriverState *bs;
+
+    for (bs = bdrv_first; bs != NULL; bs = bs->next) {
+        it(opaque, bs->device_name);
+    }
+}
+
+const char *bdrv_get_device_name(BlockDriverState *bs)
+{
+    return bs->device_name;
+}
+#endif
+
+void bdrv_flush(BlockDriverState *bs)
+{
+    if (bs->drv->bdrv_flush)
+        bs->drv->bdrv_flush(bs);
+    if (bs->backing_hd)
+        bdrv_flush(bs->backing_hd);
+}
+
+#ifndef IOEMU
+void bdrv_info(void)
+{
+    BlockDriverState *bs;
+
+    for (bs = bdrv_first; bs != NULL; bs = bs->next) {
+        term_printf("%s:", bs->device_name);
+        term_printf(" type=");
+        switch(bs->type) {
+        case BDRV_TYPE_HD:
+            term_printf("hd");
+            break;
+        case BDRV_TYPE_CDROM:
+            term_printf("cdrom");
+            break;
+        case BDRV_TYPE_FLOPPY:
+            term_printf("floppy");
+            break;
+        }
+        term_printf(" removable=%d", bs->removable);
+        if (bs->removable) {
+            term_printf(" locked=%d", bs->locked);
+        }
+        if (bs->drv) {
+            term_printf(" file=");
+           term_print_filename(bs->filename);
+            if (bs->backing_file[0] != '\0') {
+                term_printf(" backing_file=");
+               term_print_filename(bs->backing_file);
+           }
+            term_printf(" ro=%d", bs->read_only);
+            term_printf(" drv=%s", bs->drv->format_name);
+            if (bs->encrypted)
+                term_printf(" encrypted");
+        } else {
+            term_printf(" [not inserted]");
+        }
+        term_printf("\n");
+    }
+}
+
+void bdrv_get_backing_filename(BlockDriverState *bs,
+                               char *filename, int filename_size)
+{
+    if (!bs->backing_hd) {
+        pstrcpy(filename, filename_size, "");
+    } else {
+        pstrcpy(filename, filename_size, bs->backing_file);
+    }
+}
+
+int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
+                          const uint8_t *buf, int nb_sectors)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_write_compressed)
+        return -ENOTSUP;
+    return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
+}
+
+int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_get_info)
+        return -ENOTSUP;
+    memset(bdi, 0, sizeof(*bdi));
+    return drv->bdrv_get_info(bs, bdi);
+}
+
+/**************************************************************/
+/* handling of snapshots */
+
+int bdrv_snapshot_create(BlockDriverState *bs,
+                         QEMUSnapshotInfo *sn_info)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_snapshot_create)
+        return -ENOTSUP;
+    return drv->bdrv_snapshot_create(bs, sn_info);
+}
+
+int bdrv_snapshot_goto(BlockDriverState *bs,
+                       const char *snapshot_id)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_snapshot_goto)
+        return -ENOTSUP;
+    return drv->bdrv_snapshot_goto(bs, snapshot_id);
+}
+
+int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_snapshot_delete)
+        return -ENOTSUP;
+    return drv->bdrv_snapshot_delete(bs, snapshot_id);
+}
+
+int bdrv_snapshot_list(BlockDriverState *bs,
+                       QEMUSnapshotInfo **psn_info)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_snapshot_list)
+        return -ENOTSUP;
+    return drv->bdrv_snapshot_list(bs, psn_info);
+}
+
+#define NB_SUFFIXES 4
+
+char *get_human_readable_size(char *buf, int buf_size, int64_t size)
+{
+    static const char suffixes[NB_SUFFIXES] = "KMGT";
+    int64_t base;
+    int i;
+
+    if (size <= 999) {
+        snprintf(buf, buf_size, "%" PRId64, size);
+    } else {
+        base = 1024;
+        for(i = 0; i < NB_SUFFIXES; i++) {
+            if (size < (10 * base)) {
+                snprintf(buf, buf_size, "%0.1f%c",
+                         (double)size / base,
+                         suffixes[i]);
+                break;
+            } else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) {
+                snprintf(buf, buf_size, "%" PRId64 "%c",
+                         ((size + (base >> 1)) / base),
+                         suffixes[i]);
+                break;
+            }
+            base = base * 1024;
+        }
+    }
+    return buf;
+}
+
+char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn)
+{
+    char buf1[128], date_buf[128], clock_buf[128];
+#ifdef _WIN32
+    struct tm *ptm;
+#else
+    struct tm tm;
+#endif
+    time_t ti;
+    int64_t secs;
+
+    if (!sn) {
+        snprintf(buf, buf_size,
+                 "%-10s%-20s%7s%20s%15s",
+                 "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK");
+    } else {
+        ti = sn->date_sec;
+#ifdef _WIN32
+        ptm = localtime(&ti);
+        strftime(date_buf, sizeof(date_buf),
+                 "%Y-%m-%d %H:%M:%S", ptm);
+#else
+        localtime_r(&ti, &tm);
+        strftime(date_buf, sizeof(date_buf),
+                 "%Y-%m-%d %H:%M:%S", &tm);
+#endif
+        secs = sn->vm_clock_nsec / 1000000000;
+        snprintf(clock_buf, sizeof(clock_buf),
+                 "%02d:%02d:%02d.%03d",
+                 (int)(secs / 3600),
+                 (int)((secs / 60) % 60),
+                 (int)(secs % 60),
+                 (int)((sn->vm_clock_nsec / 1000000) % 1000));
+        snprintf(buf, buf_size,
+                 "%-10s%-20s%7s%20s%15s",
+                 sn->id_str, sn->name,
+                 get_human_readable_size(buf1, sizeof(buf1), 
sn->vm_state_size),
+                 date_buf,
+                 clock_buf);
+    }
+    return buf;
+}
+#endif
+
+
+/**************************************************************/
+/* async I/Os */
+
+BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
+                                uint8_t *buf, int nb_sectors,
+                                BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockDriver *drv = bs->drv;
+
+    if (!drv)
+        return NULL;
+
+    /* XXX: we assume that nb_sectors == 0 is suppored by the async read */
+    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
+        memcpy(buf, bs->boot_sector_data, 512);
+        sector_num++;
+        nb_sectors--;
+        buf += 512;
+    }
+
+    return drv->bdrv_aio_read(bs, sector_num, buf, nb_sectors, cb, opaque);
+}
+
+BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num,
+                                 const uint8_t *buf, int nb_sectors,
+                                 BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockDriver *drv = bs->drv;
+
+    if (!drv)
+        return NULL;
+    if (bs->read_only)
+        return NULL;
+    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
+        memcpy(bs->boot_sector_data, buf, 512);
+    }
+
+    return drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque);
+}
+
+void bdrv_aio_cancel(BlockDriverAIOCB *acb)
+{
+    BlockDriver *drv = acb->bs->drv;
+
+    drv->bdrv_aio_cancel(acb);
+}
+
+/**************************************************************/
+/* async block device emulation */
+
+#ifdef IOEMU
+#define QEMU_TOOL
+#endif
+#ifdef QEMU_TOOL
+static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,
+        int64_t sector_num, uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    int ret;
+    ret = bdrv_read(bs, sector_num, buf, nb_sectors);
+    cb(opaque, ret);
+    return NULL;
+}
+
+static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs,
+        int64_t sector_num, const uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    int ret;
+    ret = bdrv_write(bs, sector_num, buf, nb_sectors);
+    cb(opaque, ret);
+    return NULL;
+}
+
+static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb)
+{
+}
+#else
+static void bdrv_aio_bh_cb(void *opaque)
+{
+    BlockDriverAIOCBSync *acb = opaque;
+    acb->common.cb(acb->common.opaque, acb->ret);
+    qemu_aio_release(acb);
+}
+
+static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,
+        int64_t sector_num, uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockDriverAIOCBSync *acb;
+    int ret;
+
+    acb = qemu_aio_get(bs, cb, opaque);
+    if (!acb->bh)
+        acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
+    ret = bdrv_read(bs, sector_num, buf, nb_sectors);
+    acb->ret = ret;
+    qemu_bh_schedule(acb->bh);
+    return &acb->common;
+}
+
+static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs,
+        int64_t sector_num, const uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockDriverAIOCBSync *acb;
+    int ret;
+
+    acb = qemu_aio_get(bs, cb, opaque);
+    if (!acb->bh)
+        acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
+    ret = bdrv_write(bs, sector_num, buf, nb_sectors);
+    acb->ret = ret;
+    qemu_bh_schedule(acb->bh);
+    return &acb->common;
+}
+
+static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb)
+{
+    BlockDriverAIOCBSync *acb = (BlockDriverAIOCBSync *)blockacb;
+    qemu_bh_cancel(acb->bh);
+    qemu_aio_release(acb);
+}
+#endif /* !QEMU_TOOL */
+
+#ifndef IOEMU
+
+/**************************************************************/
+/* sync block device emulation */
+
+static void bdrv_rw_em_cb(void *opaque, int ret)
+{
+    *(int *)opaque = ret;
+}
+
+#define NOT_DONE 0x7fffffff
+
+static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
+                        uint8_t *buf, int nb_sectors)
+{
+    int async_ret;
+    BlockDriverAIOCB *acb;
+
+    async_ret = NOT_DONE;
+    qemu_aio_wait_start();
+    acb = bdrv_aio_read(bs, sector_num, buf, nb_sectors,
+                        bdrv_rw_em_cb, &async_ret);
+    if (acb == NULL) {
+        qemu_aio_wait_end();
+        return -1;
+    }
+    while (async_ret == NOT_DONE) {
+        qemu_aio_wait();
+    }
+    qemu_aio_wait_end();
+    return async_ret;
+}
+
+static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
+                         const uint8_t *buf, int nb_sectors)
+{
+    int async_ret;
+    BlockDriverAIOCB *acb;
+
+    async_ret = NOT_DONE;
+    qemu_aio_wait_start();
+    acb = bdrv_aio_write(bs, sector_num, buf, nb_sectors,
+                         bdrv_rw_em_cb, &async_ret);
+    if (acb == NULL) {
+        qemu_aio_wait_end();
+        return -1;
+    }
+    while (async_ret == NOT_DONE) {
+        qemu_aio_wait();
+    }
+    qemu_aio_wait_end();
+    return async_ret;
+}
+
+void bdrv_init(void)
+{
+    bdrv_register(&bdrv_raw);
+    bdrv_register(&bdrv_host_device);
+#ifndef _WIN32
+    bdrv_register(&bdrv_cow);
+#endif
+    bdrv_register(&bdrv_qcow);
+    bdrv_register(&bdrv_vmdk);
+    bdrv_register(&bdrv_cloop);
+    bdrv_register(&bdrv_dmg);
+    bdrv_register(&bdrv_bochs);
+    bdrv_register(&bdrv_vpc);
+    bdrv_register(&bdrv_vvfat);
+    bdrv_register(&bdrv_qcow2);
+    bdrv_register(&bdrv_parallels);
+}
+
+void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
+                   void *opaque)
+{
+    BlockDriver *drv;
+    BlockDriverAIOCB *acb;
+
+    drv = bs->drv;
+    if (drv->free_aiocb) {
+        acb = drv->free_aiocb;
+        drv->free_aiocb = acb->next;
+    } else {
+        acb = qemu_mallocz(drv->aiocb_size);
+        if (!acb)
+            return NULL;
+    }
+    acb->bs = bs;
+    acb->cb = cb;
+    acb->opaque = opaque;
+    return acb;
+}
+
+void qemu_aio_release(void *p)
+{
+    BlockDriverAIOCB *acb = p;
+    BlockDriver *drv = acb->bs->drv;
+    acb->next = drv->free_aiocb;
+    drv->free_aiocb = acb;
+}
+#endif
+
+/**************************************************************/
+/* removable device support */
+
+/**
+ * Return TRUE if the media is present
+ */
+int bdrv_is_inserted(BlockDriverState *bs)
+{
+    BlockDriver *drv = bs->drv;
+    int ret;
+    if (!drv)
+        return 0;
+    if (!drv->bdrv_is_inserted)
+        return 1;
+    ret = drv->bdrv_is_inserted(bs);
+    return ret;
+}
+
+/**
+ * Return TRUE if the media changed since the last call to this
+ * function. It is currently only used for floppy disks
+ */
+int bdrv_media_changed(BlockDriverState *bs)
+{
+    BlockDriver *drv = bs->drv;
+    int ret;
+
+    if (!drv || !drv->bdrv_media_changed)
+        ret = -ENOTSUP;
+    else
+        ret = drv->bdrv_media_changed(bs);
+    if (ret == -ENOTSUP)
+        ret = bs->media_changed;
+    bs->media_changed = 0;
+    return ret;
+}
+
+/**
+ * If eject_flag is TRUE, eject the media. Otherwise, close the tray
+ */
+void bdrv_eject(BlockDriverState *bs, int eject_flag)
+{
+    BlockDriver *drv = bs->drv;
+    int ret;
+
+    if (!drv || !drv->bdrv_eject) {
+        ret = -ENOTSUP;
+    } else {
+        ret = drv->bdrv_eject(bs, eject_flag);
+    }
+    if (ret == -ENOTSUP) {
+        if (eject_flag)
+            bdrv_close(bs);
+    }
+}
+
+int bdrv_is_locked(BlockDriverState *bs)
+{
+    return bs->locked;
+}
+
+/**
+ * Lock or unlock the media (if it is locked, the user won't be able
+ * to eject it manually).
+ */
+void bdrv_set_locked(BlockDriverState *bs, int locked)
+{
+    BlockDriver *drv = bs->drv;
+
+    bs->locked = locked;
+    if (drv && drv->bdrv_set_locked) {
+        drv->bdrv_set_locked(bs, locked);
+    }
+}
diff -r 092232fa1fbd extras/stubfw/ioemu/block_int.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/ioemu/block_int.h   Thu Nov 15 02:08:10 2007 +0100
@@ -0,0 +1,136 @@
+/*
+ * QEMU System Emulator block driver
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef BLOCK_INT_H
+#define BLOCK_INT_H
+
+#define BLOCK_FLAG_ENCRYPT     1
+#define BLOCK_FLAG_COMPRESS    2
+#define BLOCK_FLAG_COMPAT6     4
+
+struct BlockDriver {
+    const char *format_name;
+    int instance_size;
+    int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
+    int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags);
+    int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
+                     uint8_t *buf, int nb_sectors);
+    int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
+                      const uint8_t *buf, int nb_sectors);
+    void (*bdrv_close)(BlockDriverState *bs);
+    int (*bdrv_create)(const char *filename, int64_t total_sectors,
+                       const char *backing_file, int flags);
+    void (*bdrv_flush)(BlockDriverState *bs);
+    int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
+                             int nb_sectors, int *pnum);
+    int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
+    int (*bdrv_make_empty)(BlockDriverState *bs);
+    /* aio */
+    BlockDriverAIOCB *(*bdrv_aio_read)(BlockDriverState *bs,
+        int64_t sector_num, uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
+    BlockDriverAIOCB *(*bdrv_aio_write)(BlockDriverState *bs,
+        int64_t sector_num, const uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
+    void (*bdrv_aio_cancel)(BlockDriverAIOCB *acb);
+    int aiocb_size;
+
+    const char *protocol_name;
+    int (*bdrv_pread)(BlockDriverState *bs, int64_t offset,
+                      uint8_t *buf, int count);
+    int (*bdrv_pwrite)(BlockDriverState *bs, int64_t offset,
+                       const uint8_t *buf, int count);
+    int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
+    int64_t (*bdrv_getlength)(BlockDriverState *bs);
+    int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num,
+                                 const uint8_t *buf, int nb_sectors);
+
+    int (*bdrv_snapshot_create)(BlockDriverState *bs,
+                                QEMUSnapshotInfo *sn_info);
+    int (*bdrv_snapshot_goto)(BlockDriverState *bs,
+                              const char *snapshot_id);
+    int (*bdrv_snapshot_delete)(BlockDriverState *bs, const char *snapshot_id);
+    int (*bdrv_snapshot_list)(BlockDriverState *bs,
+                              QEMUSnapshotInfo **psn_info);
+    int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
+
+    /* removable device specific */
+    int (*bdrv_is_inserted)(BlockDriverState *bs);
+    int (*bdrv_media_changed)(BlockDriverState *bs);
+    int (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
+    int (*bdrv_set_locked)(BlockDriverState *bs, int locked);
+
+    BlockDriverAIOCB *free_aiocb;
+    struct BlockDriver *next;
+};
+
+struct BlockDriverState {
+    int64_t total_sectors; /* if we are reading a disk image, give its
+                              size in sectors */
+    int read_only; /* if true, the media is read only */
+    int removable; /* if true, the media can be removed */
+    int locked;    /* if true, the media cannot temporarily be ejected */
+    int encrypted; /* if true, the media is encrypted */
+    /* event callback when inserting/removing */
+    void (*change_cb)(void *opaque);
+    void *change_opaque;
+
+    BlockDriver *drv; /* NULL means no media */
+    void *opaque;
+
+    int boot_sector_enabled;
+    uint8_t boot_sector_data[512];
+
+    char filename[1024];
+    char backing_file[1024]; /* if non zero, the image is a diff of
+                                this file image */
+    int is_temporary;
+    int media_changed;
+
+    BlockDriverState *backing_hd;
+    /* async read/write emulation */
+
+    void *sync_aiocb;
+
+    /* NOTE: the following infos are only hints for real hardware
+       drivers. They are not used by the block driver */
+    int cyls, heads, secs, translation;
+    int type;
+    char device_name[32];
+    BlockDriverState *next;
+};
+
+struct BlockDriverAIOCB {
+    BlockDriverState *bs;
+    BlockDriverCompletionFunc *cb;
+    void *opaque;
+    BlockDriverAIOCB *next;
+};
+
+void get_tmp_filename(char *filename, int size);
+
+void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
+                   void *opaque);
+void qemu_aio_release(void *p);
+
+#endif /* BLOCK_INT_H */
diff -r 092232fa1fbd extras/stubfw/ioemu/cdrom.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/ioemu/cdrom.c       Wed Nov 14 07:02:20 2007 +0100
@@ -0,0 +1,156 @@
+/*
+ * QEMU ATAPI CD-ROM Emulator
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* ??? Most of the ATAPI emulation is still in ide.c.  It should be moved
+   here.  */
+
+#include "vl.h"
+
+static void lba_to_msf(uint8_t *buf, int lba)
+{
+    lba += 150;
+    buf[0] = (lba / 75) / 60;
+    buf[1] = (lba / 75) % 60;
+    buf[2] = lba % 75;
+}
+
+/* same toc as bochs. Return -1 if error or the toc length */
+/* XXX: check this */
+int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track)
+{
+    uint8_t *q;
+    int len;
+
+    if (start_track > 1 && start_track != 0xaa)
+        return -1;
+    q = buf + 2;
+    *q++ = 1; /* first session */
+    *q++ = 1; /* last session */
+    if (start_track <= 1) {
+        *q++ = 0; /* reserved */
+        *q++ = 0x14; /* ADR, control */
+        *q++ = 1;    /* track number */
+        *q++ = 0; /* reserved */
+        if (msf) {
+            *q++ = 0; /* reserved */
+            lba_to_msf(q, 0);
+            q += 3;
+        } else {
+            /* sector 0 */
+            cpu_to_be32wu((uint32_t *)q, 0);
+            q += 4;
+        }
+    }
+    /* lead out track */
+    *q++ = 0; /* reserved */
+    *q++ = 0x16; /* ADR, control */
+    *q++ = 0xaa; /* track number */
+    *q++ = 0; /* reserved */
+    if (msf) {
+        *q++ = 0; /* reserved */
+        lba_to_msf(q, nb_sectors);
+        q += 3;
+    } else {
+        cpu_to_be32wu((uint32_t *)q, nb_sectors);
+        q += 4;
+    }
+    len = q - buf;
+    cpu_to_be16wu((uint16_t *)buf, len - 2);
+    return len;
+}
+
+/* mostly same info as PearPc */
+int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num)
+{
+    uint8_t *q;
+    int len;
+
+    q = buf + 2;
+    *q++ = 1; /* first session */
+    *q++ = 1; /* last session */
+
+    *q++ = 1; /* session number */
+    *q++ = 0x14; /* data track */
+    *q++ = 0; /* track number */
+    *q++ = 0xa0; /* lead-in */
+    *q++ = 0; /* min */
+    *q++ = 0; /* sec */
+    *q++ = 0; /* frame */
+    *q++ = 0;
+    *q++ = 1; /* first track */
+    *q++ = 0x00; /* disk type */
+    *q++ = 0x00;
+
+    *q++ = 1; /* session number */
+    *q++ = 0x14; /* data track */
+    *q++ = 0; /* track number */
+    *q++ = 0xa1;
+    *q++ = 0; /* min */
+    *q++ = 0; /* sec */
+    *q++ = 0; /* frame */
+    *q++ = 0;
+    *q++ = 1; /* last track */
+    *q++ = 0x00;
+    *q++ = 0x00;
+
+    *q++ = 1; /* session number */
+    *q++ = 0x14; /* data track */
+    *q++ = 0; /* track number */
+    *q++ = 0xa2; /* lead-out */
+    *q++ = 0; /* min */
+    *q++ = 0; /* sec */
+    *q++ = 0; /* frame */
+    if (msf) {
+        *q++ = 0; /* reserved */
+        lba_to_msf(q, nb_sectors);
+        q += 3;
+    } else {
+        cpu_to_be32wu((uint32_t *)q, nb_sectors);
+        q += 4;
+    }
+
+    *q++ = 1; /* session number */
+    *q++ = 0x14; /* ADR, control */
+    *q++ = 0;    /* track number */
+    *q++ = 1;    /* point */
+    *q++ = 0; /* min */
+    *q++ = 0; /* sec */
+    *q++ = 0; /* frame */
+    if (msf) {
+        *q++ = 0;
+        lba_to_msf(q, 0);
+        q += 3;
+    } else {
+        *q++ = 0;
+        *q++ = 0;
+        *q++ = 0;
+        *q++ = 0;
+    }
+
+    len = q - buf;
+    cpu_to_be16wu((uint16_t *)buf, len - 2);
+    return len;
+}
+
+
diff -r 092232fa1fbd extras/stubfw/ioemu/ide.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/ioemu/ide.c Mon Nov 19 02:16:07 2007 +0100
@@ -0,0 +1,3709 @@
+/*
+ * QEMU IDE disk and CD-ROM Emulator
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ * Copyright (c) 2006 Openedhand Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+#ifdef IOEMU
+#include "gnttab.h"
+#include "hypervisor.h"
+#endif
+
+/* debug IDE devices */
+//#define DEBUG_IDE
+//#define DEBUG_IDE_ATAPI
+//#define DEBUG_AIO
+#define USE_DMA_CDROM
+
+/* Bits of HD_STATUS */
+#define ERR_STAT               0x01
+#define INDEX_STAT             0x02
+#define ECC_STAT               0x04    /* Corrected error */
+#define DRQ_STAT               0x08
+#define SEEK_STAT              0x10
+#define SRV_STAT               0x10
+#define WRERR_STAT             0x20
+#define READY_STAT             0x40
+#define BUSY_STAT              0x80
+
+/* Bits for HD_ERROR */
+#define MARK_ERR               0x01    /* Bad address mark */
+#define TRK0_ERR               0x02    /* couldn't find track 0 */
+#define ABRT_ERR               0x04    /* Command aborted */
+#define MCR_ERR                        0x08    /* media change request */
+#define ID_ERR                 0x10    /* ID field not found */
+#define MC_ERR                 0x20    /* media changed */
+#define ECC_ERR                        0x40    /* Uncorrectable ECC error */
+#define BBD_ERR                        0x80    /* pre-EIDE meaning:  block 
marked bad */
+#define ICRC_ERR               0x80    /* new meaning:  CRC error during 
transfer */
+
+/* Bits of HD_NSECTOR */
+#define CD                     0x01
+#define IO                     0x02
+#define REL                    0x04
+#define TAG_MASK               0xf8
+
+#define IDE_CMD_RESET           0x04
+#define IDE_CMD_DISABLE_IRQ     0x02
+
+/* ATA/ATAPI Commands pre T13 Spec */
+#define WIN_NOP                                0x00
+/*
+ *     0x01->0x02 Reserved
+ */
+#define CFA_REQ_EXT_ERROR_CODE         0x03 /* CFA Request Extended Error Code 
*/
+/*
+ *     0x04->0x07 Reserved
+ */
+#define WIN_SRST                       0x08 /* ATAPI soft reset command */
+#define WIN_DEVICE_RESET               0x08
+/*
+ *     0x09->0x0F Reserved
+ */
+#define WIN_RECAL                      0x10
+#define WIN_RESTORE                    WIN_RECAL
+/*
+ *     0x10->0x1F Reserved
+ */
+#define WIN_READ                       0x20 /* 28-Bit */
+#define WIN_READ_ONCE                  0x21 /* 28-Bit without retries */
+#define WIN_READ_LONG                  0x22 /* 28-Bit */
+#define WIN_READ_LONG_ONCE             0x23 /* 28-Bit without retries */
+#define WIN_READ_EXT                   0x24 /* 48-Bit */
+#define WIN_READDMA_EXT                        0x25 /* 48-Bit */
+#define WIN_READDMA_QUEUED_EXT         0x26 /* 48-Bit */
+#define WIN_READ_NATIVE_MAX_EXT                0x27 /* 48-Bit */
+/*
+ *     0x28
+ */
+#define WIN_MULTREAD_EXT               0x29 /* 48-Bit */
+/*
+ *     0x2A->0x2F Reserved
+ */
+#define WIN_WRITE                      0x30 /* 28-Bit */
+#define WIN_WRITE_ONCE                 0x31 /* 28-Bit without retries */
+#define WIN_WRITE_LONG                 0x32 /* 28-Bit */
+#define WIN_WRITE_LONG_ONCE            0x33 /* 28-Bit without retries */
+#define WIN_WRITE_EXT                  0x34 /* 48-Bit */
+#define WIN_WRITEDMA_EXT               0x35 /* 48-Bit */
+#define WIN_WRITEDMA_QUEUED_EXT                0x36 /* 48-Bit */
+#define WIN_SET_MAX_EXT                        0x37 /* 48-Bit */
+#define CFA_WRITE_SECT_WO_ERASE                0x38 /* CFA Write Sectors 
without erase */
+#define WIN_MULTWRITE_EXT              0x39 /* 48-Bit */
+/*
+ *     0x3A->0x3B Reserved
+ */
+#define WIN_WRITE_VERIFY               0x3C /* 28-Bit */
+/*
+ *     0x3D->0x3F Reserved
+ */
+#define WIN_VERIFY                     0x40 /* 28-Bit - Read Verify Sectors */
+#define WIN_VERIFY_ONCE                        0x41 /* 28-Bit - without 
retries */
+#define WIN_VERIFY_EXT                 0x42 /* 48-Bit */
+/*
+ *     0x43->0x4F Reserved
+ */
+#define WIN_FORMAT                     0x50
+/*
+ *     0x51->0x5F Reserved
+ */
+#define WIN_INIT                       0x60
+/*
+ *     0x61->0x5F Reserved
+ */
+#define WIN_SEEK                       0x70 /* 0x70-0x7F Reserved */
+#define CFA_TRANSLATE_SECTOR           0x87 /* CFA Translate Sector */
+#define WIN_DIAGNOSE                   0x90
+#define WIN_SPECIFY                    0x91 /* set drive geometry translation 
*/
+#define WIN_DOWNLOAD_MICROCODE         0x92
+#define WIN_STANDBYNOW2                        0x94
+#define CFA_IDLEIMMEDIATE              0x95 /* force drive to become "ready" */
+#define WIN_STANDBY2                   0x96
+#define WIN_SETIDLE2                   0x97
+#define WIN_CHECKPOWERMODE2            0x98
+#define WIN_SLEEPNOW2                  0x99
+/*
+ *     0x9A VENDOR
+ */
+#define WIN_PACKETCMD                  0xA0 /* Send a packet command. */
+#define WIN_PIDENTIFY                  0xA1 /* identify ATAPI device   */
+#define WIN_QUEUED_SERVICE             0xA2
+#define WIN_SMART                      0xB0 /* self-monitoring and reporting */
+#define CFA_ACCESS_METADATA_STORAGE    0xB8
+#define CFA_ERASE_SECTORS              0xC0 /* microdrives implement as NOP */
+#define WIN_MULTREAD                   0xC4 /* read sectors using multiple 
mode*/
+#define WIN_MULTWRITE                  0xC5 /* write sectors using multiple 
mode */
+#define WIN_SETMULT                    0xC6 /* enable/disable multiple mode */
+#define WIN_READDMA_QUEUED             0xC7 /* read sectors using Queued DMA 
transfers */
+#define WIN_READDMA                    0xC8 /* read sectors using DMA 
transfers */
+#define WIN_READDMA_ONCE               0xC9 /* 28-Bit - without retries */
+#define WIN_WRITEDMA                   0xCA /* write sectors using DMA 
transfers */
+#define WIN_WRITEDMA_ONCE              0xCB /* 28-Bit - without retries */
+#define WIN_WRITEDMA_QUEUED            0xCC /* write sectors using Queued DMA 
transfers */
+#define CFA_WRITE_MULTI_WO_ERASE       0xCD /* CFA Write multiple without 
erase */
+#define WIN_GETMEDIASTATUS             0xDA
+#define WIN_ACKMEDIACHANGE             0xDB /* ATA-1, ATA-2 vendor */
+#define WIN_POSTBOOT                   0xDC
+#define WIN_PREBOOT                    0xDD
+#define WIN_DOORLOCK                   0xDE /* lock door on removable drives */
+#define WIN_DOORUNLOCK                 0xDF /* unlock door on removable drives 
*/
+#define WIN_STANDBYNOW1                        0xE0
+#define WIN_IDLEIMMEDIATE              0xE1 /* force drive to become "ready" */
+#define WIN_STANDBY                    0xE2 /* Set device in Standby Mode */
+#define WIN_SETIDLE1                   0xE3
+#define WIN_READ_BUFFER                        0xE4 /* force read only 1 
sector */
+#define WIN_CHECKPOWERMODE1            0xE5
+#define WIN_SLEEPNOW1                  0xE6
+#define WIN_FLUSH_CACHE                        0xE7
+#define WIN_WRITE_BUFFER               0xE8 /* force write only 1 sector */
+#define WIN_WRITE_SAME                 0xE9 /* read ata-2 to use */
+       /* SET_FEATURES 0x22 or 0xDD */
+#define WIN_FLUSH_CACHE_EXT            0xEA /* 48-Bit */
+#define WIN_IDENTIFY                   0xEC /* ask drive to identify itself    
*/
+#define WIN_MEDIAEJECT                 0xED
+#define WIN_IDENTIFY_DMA               0xEE /* same as WIN_IDENTIFY, but DMA */
+#define WIN_SETFEATURES                        0xEF /* set special drive 
features */
+#define EXABYTE_ENABLE_NEST            0xF0
+#define IBM_SENSE_CONDITION            0xF0 /* measure disk temperature */
+#define WIN_SECURITY_SET_PASS          0xF1
+#define WIN_SECURITY_UNLOCK            0xF2
+#define WIN_SECURITY_ERASE_PREPARE     0xF3
+#define WIN_SECURITY_ERASE_UNIT                0xF4
+#define WIN_SECURITY_FREEZE_LOCK       0xF5
+#define CFA_WEAR_LEVEL                 0xF5 /* microdrives implement as NOP */
+#define WIN_SECURITY_DISABLE           0xF6
+#define WIN_READ_NATIVE_MAX            0xF8 /* return the native maximum 
address */
+#define WIN_SET_MAX                    0xF9
+#define DISABLE_SEAGATE                        0xFB
+
+/* set to 1 set disable mult support */
+#define MAX_MULT_SECTORS 16
+
+/* ATAPI defines */
+
+#define ATAPI_PACKET_SIZE 12
+
+/* The generic packet command opcodes for CD/DVD Logical Units,
+ * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+#define GPCMD_BLANK                        0xa1
+#define GPCMD_CLOSE_TRACK                  0x5b
+#define GPCMD_FLUSH_CACHE                  0x35
+#define GPCMD_FORMAT_UNIT                  0x04
+#define GPCMD_GET_CONFIGURATION                    0x46
+#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a
+#define GPCMD_GET_PERFORMANCE              0xac
+#define GPCMD_INQUIRY                      0x12
+#define GPCMD_LOAD_UNLOAD                  0xa6
+#define GPCMD_MECHANISM_STATUS             0xbd
+#define GPCMD_MODE_SELECT_10               0x55
+#define GPCMD_MODE_SENSE_10                0x5a
+#define GPCMD_PAUSE_RESUME                 0x4b
+#define GPCMD_PLAY_AUDIO_10                0x45
+#define GPCMD_PLAY_AUDIO_MSF               0x47
+#define GPCMD_PLAY_AUDIO_TI                0x48
+#define GPCMD_PLAY_CD                      0xbc
+#define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL  0x1e
+#define GPCMD_READ_10                      0x28
+#define GPCMD_READ_12                      0xa8
+#define GPCMD_READ_CDVD_CAPACITY           0x25
+#define GPCMD_READ_CD                      0xbe
+#define GPCMD_READ_CD_MSF                  0xb9
+#define GPCMD_READ_DISC_INFO               0x51
+#define GPCMD_READ_DVD_STRUCTURE           0xad
+#define GPCMD_READ_FORMAT_CAPACITIES       0x23
+#define GPCMD_READ_HEADER                  0x44
+#define GPCMD_READ_TRACK_RZONE_INFO        0x52
+#define GPCMD_READ_SUBCHANNEL              0x42
+#define GPCMD_READ_TOC_PMA_ATIP                    0x43
+#define GPCMD_REPAIR_RZONE_TRACK           0x58
+#define GPCMD_REPORT_KEY                   0xa4
+#define GPCMD_REQUEST_SENSE                0x03
+#define GPCMD_RESERVE_RZONE_TRACK          0x53
+#define GPCMD_SCAN                         0xba
+#define GPCMD_SEEK                         0x2b
+#define GPCMD_SEND_DVD_STRUCTURE           0xad
+#define GPCMD_SEND_EVENT                   0xa2
+#define GPCMD_SEND_KEY                     0xa3
+#define GPCMD_SEND_OPC                     0x54
+#define GPCMD_SET_READ_AHEAD               0xa7
+#define GPCMD_SET_STREAMING                0xb6
+#define GPCMD_START_STOP_UNIT              0x1b
+#define GPCMD_STOP_PLAY_SCAN               0x4e
+#define GPCMD_TEST_UNIT_READY              0x00
+#define GPCMD_VERIFY_10                            0x2f
+#define GPCMD_WRITE_10                     0x2a
+#define GPCMD_WRITE_AND_VERIFY_10          0x2e
+/* This is listed as optional in ATAPI 2.6, but is (curiously)
+ * missing from Mt. Fuji, Table 57.  It _is_ mentioned in Mt. Fuji
+ * Table 377 as an MMC command for SCSi devices though...  Most ATAPI
+ * drives support it. */
+#define GPCMD_SET_SPEED                            0xbb
+/* This seems to be a SCSI specific CD-ROM opcode
+ * to play data at track/index */
+#define GPCMD_PLAYAUDIO_TI                 0x48
+/*
+ * From MS Media Status Notification Support Specification. For
+ * older drives only.
+ */
+#define GPCMD_GET_MEDIA_STATUS             0xda
+#define GPCMD_MODE_SENSE_6                 0x1a
+
+/* Mode page codes for mode sense/set */
+#define GPMODE_R_W_ERROR_PAGE          0x01
+#define GPMODE_WRITE_PARMS_PAGE                0x05
+#define GPMODE_AUDIO_CTL_PAGE          0x0e
+#define GPMODE_POWER_PAGE              0x1a
+#define GPMODE_FAULT_FAIL_PAGE         0x1c
+#define GPMODE_TO_PROTECT_PAGE         0x1d
+#define GPMODE_CAPABILITIES_PAGE       0x2a
+#define GPMODE_ALL_PAGES               0x3f
+/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor
+ * of MODE_SENSE_POWER_PAGE */
+#define GPMODE_CDROM_PAGE              0x0d
+
+#define ATAPI_INT_REASON_CD             0x01 /* 0 = data transfer */
+#define ATAPI_INT_REASON_IO             0x02 /* 1 = transfer to the host */
+#define ATAPI_INT_REASON_REL            0x04
+#define ATAPI_INT_REASON_TAG            0xf8
+
+/* same constants as bochs */
+#define ASC_ILLEGAL_OPCODE                   0x20
+#define ASC_LOGICAL_BLOCK_OOR                0x21
+#define ASC_INV_FIELD_IN_CMD_PACKET          0x24
+#define ASC_MEDIUM_NOT_PRESENT               0x3a
+#define ASC_SAVING_PARAMETERS_NOT_SUPPORTED  0x39
+
+#define CFA_NO_ERROR            0x00
+#define CFA_MISC_ERROR          0x09
+#define CFA_INVALID_COMMAND     0x20
+#define CFA_INVALID_ADDRESS     0x21
+#define CFA_ADDRESS_OVERFLOW    0x2f
+
+#define SENSE_NONE            0
+#define SENSE_NOT_READY       2
+#define SENSE_ILLEGAL_REQUEST 5
+#define SENSE_UNIT_ATTENTION  6
+
+struct IDEState;
+
+typedef void EndTransferFunc(struct IDEState *);
+
+/* NOTE: IDEState represents in fact one drive */
+typedef struct IDEState {
+    /* ide config */
+    int is_cdrom;
+    int is_cf;
+    unsigned int cylinders, heads, sectors;
+    int64_t nb_sectors;
+    int mult_sectors;
+    int identify_set;
+    uint16_t identify_data[256];
+    qemu_irq irq;
+    PCIDevice *pci_dev;
+    struct BMDMAState *bmdma;
+    int drive_serial;
+    /* ide regs */
+    uint8_t feature;
+    uint8_t error;
+    uint32_t nsector;
+    uint8_t sector;
+    uint8_t lcyl;
+    uint8_t hcyl;
+    /* other part of tf for lba48 support */
+    uint8_t hob_feature;
+    uint8_t hob_nsector;
+    uint8_t hob_sector;
+    uint8_t hob_lcyl;
+    uint8_t hob_hcyl;
+
+    uint8_t select;
+    uint8_t status;
+
+    /* 0x3f6 command, only meaningful for drive 0 */
+    uint8_t cmd;
+    /* set for lba48 access */
+    uint8_t lba48;
+    /* depends on bit 4 in select, only meaningful for drive 0 */
+    struct IDEState *cur_drive;
+    BlockDriverState *bs;
+    /* ATAPI specific */
+    uint8_t sense_key;
+    uint8_t asc;
+    int packet_transfer_size;
+    int elementary_transfer_size;
+    int io_buffer_index;
+    int lba;
+    int cd_sector_size;
+    int atapi_dma; /* true if dma is requested for the packet cmd */
+    /* ATA DMA state */
+    int io_buffer_size;
+    /* PIO transfer handling */
+    int req_nb_sectors; /* number of sectors per interrupt */
+    EndTransferFunc *end_transfer_func;
+    uint8_t *data_ptr;
+    uint8_t *data_end;
+#ifdef IOEMU
+    uint8_t *io_buffer;
+#else
+    uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4];
+#endif
+#ifdef TARGET_I386
+    QEMUTimer *sector_write_timer; /* only used for win2k install hack */
+#endif
+    uint32_t irq_count; /* counts IRQs when using win2k install hack */
+    /* CF-ATA extended error */
+    uint8_t ext_error;
+    /* CF-ATA metadata storage */
+    uint32_t mdata_size;
+    uint8_t *mdata_storage;
+    int media_changed;
+} IDEState;
+
+#define BM_STATUS_DMAING 0x01
+#define BM_STATUS_ERROR  0x02
+#define BM_STATUS_INT    0x04
+
+#define BM_CMD_START     0x01
+#define BM_CMD_READ      0x08
+
+#define IDE_TYPE_PIIX3   0
+#define IDE_TYPE_CMD646  1
+#define IDE_TYPE_PIIX4   2
+
+/* CMD646 specific */
+#define MRDMODE                0x71
+#define   MRDMODE_INTR_CH0     0x04
+#define   MRDMODE_INTR_CH1     0x08
+#define   MRDMODE_BLK_CH0      0x10
+#define   MRDMODE_BLK_CH1      0x20
+#define UDIDETCR0      0x73
+#define UDIDETCR1      0x7B
+
+typedef struct BMDMAState {
+    uint8_t cmd;
+    uint8_t status;
+    uint32_t addr;
+
+    struct PCIIDEState *pci_dev;
+    /* current transfer state */
+    uint32_t cur_addr;
+    uint32_t cur_prd_last;
+    uint32_t cur_prd_addr;
+    uint32_t cur_prd_len;
+    IDEState *ide_if;
+    BlockDriverCompletionFunc *dma_cb;
+    BlockDriverAIOCB *aiocb;
+} BMDMAState;
+
+typedef struct PCIIDEState {
+    PCIDevice dev;
+    IDEState ide_if[4];
+    BMDMAState bmdma[2];
+    int type; /* see IDE_TYPE_xxx */
+} PCIIDEState;
+
+static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb);
+static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret);
+
+static void padstr(char *str, const char *src, int len)
+{
+    int i, v;
+    for(i = 0; i < len; i++) {
+        if (*src)
+            v = *src++;
+        else
+            v = ' ';
+        *(char *)((long)str ^ 1) = v;
+        str++;
+    }
+}
+
+static void padstr8(uint8_t *buf, int buf_size, const char *src)
+{
+    int i;
+    for(i = 0; i < buf_size; i++) {
+        if (*src)
+            buf[i] = *src++;
+        else
+            buf[i] = ' ';
+    }
+}
+
+static void put_le16(uint16_t *p, unsigned int v)
+{
+    *p = cpu_to_le16(v);
+}
+
+static void ide_identify(IDEState *s)
+{
+    uint16_t *p;
+    unsigned int oldsize;
+    char buf[20];
+
+    if (s->identify_set) {
+       memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data));
+       return;
+    }
+
+    memset(s->io_buffer, 0, 512);
+    p = (uint16_t *)s->io_buffer;
+    put_le16(p + 0, 0x0040);
+    put_le16(p + 1, s->cylinders);
+    put_le16(p + 3, s->heads);
+    put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */
+    put_le16(p + 5, 512); /* XXX: retired, remove ? */
+    put_le16(p + 6, s->sectors);
+    snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial);
+    padstr((uint8_t *)(p + 10), buf, 20); /* serial number */
+    put_le16(p + 20, 3); /* XXX: retired, remove ? */
+    put_le16(p + 21, 512); /* cache size in sectors */
+    put_le16(p + 22, 4); /* ecc bytes */
+    padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */
+    padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); /* model */
+#if MAX_MULT_SECTORS > 1
+    put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
+#endif
+    put_le16(p + 48, 1); /* dword I/O */
+    put_le16(p + 49, (1 << 11) | (1 << 9) | (1 << 8)); /* DMA and LBA 
supported */
+    put_le16(p + 51, 0x200); /* PIO transfer cycle */
+    put_le16(p + 52, 0x200); /* DMA transfer cycle */
+    put_le16(p + 53, 1 | (1 << 1) | (1 << 2)); /* words 54-58,64-70,88 are 
valid */
+    put_le16(p + 54, s->cylinders);
+    put_le16(p + 55, s->heads);
+    put_le16(p + 56, s->sectors);
+    oldsize = s->cylinders * s->heads * s->sectors;
+    put_le16(p + 57, oldsize);
+    put_le16(p + 58, oldsize >> 16);
+    if (s->mult_sectors)
+        put_le16(p + 59, 0x100 | s->mult_sectors);
+    put_le16(p + 60, s->nb_sectors);
+    put_le16(p + 61, s->nb_sectors >> 16);
+    put_le16(p + 63, 0x07); /* mdma0-2 supported */
+    put_le16(p + 65, 120);
+    put_le16(p + 66, 120);
+    put_le16(p + 67, 120);
+    put_le16(p + 68, 120);
+    put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */
+    put_le16(p + 81, 0x16); /* conforms to ata5 */
+    put_le16(p + 82, (1 << 14));
+    /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
+    put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
+    put_le16(p + 84, (1 << 14));
+    put_le16(p + 85, (1 << 14));
+    /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
+    put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
+    put_le16(p + 87, (1 << 14));
+    put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
+    put_le16(p + 93, 1 | (1 << 14) | 0x2000);
+    put_le16(p + 100, s->nb_sectors);
+    put_le16(p + 101, s->nb_sectors >> 16);
+    put_le16(p + 102, s->nb_sectors >> 32);
+    put_le16(p + 103, s->nb_sectors >> 48);
+
+    memcpy(s->identify_data, p, sizeof(s->identify_data));
+    s->identify_set = 1;
+}
+
+static void ide_atapi_identify(IDEState *s)
+{
+    uint16_t *p;
+    char buf[20];
+
+    if (s->identify_set) {
+       memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data));
+       return;
+    }
+
+    memset(s->io_buffer, 0, 512);
+    p = (uint16_t *)s->io_buffer;
+    /* Removable CDROM, 50us response, 12 byte packets */
+    put_le16(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0));
+    snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial);
+    padstr((uint8_t *)(p + 10), buf, 20); /* serial number */
+    put_le16(p + 20, 3); /* buffer type */
+    put_le16(p + 21, 512); /* cache size in sectors */
+    put_le16(p + 22, 4); /* ecc bytes */
+    padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */
+    padstr((uint8_t *)(p + 27), "QEMU CD-ROM", 40); /* model */
+    put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
+#ifdef USE_DMA_CDROM
+    put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */
+    put_le16(p + 53, 7); /* words 64-70, 54-58, 88 valid */
+    put_le16(p + 63, 7);  /* mdma0-2 supported */
+    put_le16(p + 64, 0x3f); /* PIO modes supported */
+#else
+    put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */
+    put_le16(p + 53, 3); /* words 64-70, 54-58 valid */
+    put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */
+    put_le16(p + 64, 1); /* PIO modes */
+#endif
+    put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */
+    put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */
+    put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */
+    put_le16(p + 68, 0xb4); /* minimum PIO cycle time with IORDY flow control 
*/
+
+    put_le16(p + 71, 30); /* in ns */
+    put_le16(p + 72, 30); /* in ns */
+
+    put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */
+#ifdef USE_DMA_CDROM
+    put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
+#endif
+    memcpy(s->identify_data, p, sizeof(s->identify_data));
+    s->identify_set = 1;
+}
+
+static void ide_cfata_identify(IDEState *s)
+{
+    uint16_t *p;
+    uint32_t cur_sec;
+    char buf[20];
+
+    p = (uint16_t *) s->identify_data;
+    if (s->identify_set)
+        goto fill_buffer;
+
+    memset(p, 0, sizeof(s->identify_data));
+
+    cur_sec = s->cylinders * s->heads * s->sectors;
+
+    put_le16(p + 0, 0x848a);                   /* CF Storage Card signature */
+    put_le16(p + 1, s->cylinders);             /* Default cylinders */
+    put_le16(p + 3, s->heads);                 /* Default heads */
+    put_le16(p + 6, s->sectors);               /* Default sectors per track */
+    put_le16(p + 7, s->nb_sectors >> 16);      /* Sectors per card */
+    put_le16(p + 8, s->nb_sectors);            /* Sectors per card */
+    snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial);
+    padstr((uint8_t *)(p + 10), buf, 20);      /* Serial number in ASCII */
+    put_le16(p + 22, 0x0004);                  /* ECC bytes */
+    padstr((uint8_t *) (p + 23), QEMU_VERSION, 8);     /* Firmware Revision */
+    padstr((uint8_t *) (p + 27), "QEMU MICRODRIVE", 40);/* Model number */
+#if MAX_MULT_SECTORS > 1
+    put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
+#else
+    put_le16(p + 47, 0x0000);
+#endif
+    put_le16(p + 49, 0x0f00);                  /* Capabilities */
+    put_le16(p + 51, 0x0002);                  /* PIO cycle timing mode */
+    put_le16(p + 52, 0x0001);                  /* DMA cycle timing mode */
+    put_le16(p + 53, 0x0003);                  /* Translation params valid */
+    put_le16(p + 54, s->cylinders);            /* Current cylinders */
+    put_le16(p + 55, s->heads);                        /* Current heads */
+    put_le16(p + 56, s->sectors);              /* Current sectors */
+    put_le16(p + 57, cur_sec);                 /* Current capacity */
+    put_le16(p + 58, cur_sec >> 16);           /* Current capacity */
+    if (s->mult_sectors)                       /* Multiple sector setting */
+        put_le16(p + 59, 0x100 | s->mult_sectors);
+    put_le16(p + 60, s->nb_sectors);           /* Total LBA sectors */
+    put_le16(p + 61, s->nb_sectors >> 16);     /* Total LBA sectors */
+    put_le16(p + 63, 0x0203);                  /* Multiword DMA capability */
+    put_le16(p + 64, 0x0001);                  /* Flow Control PIO support */
+    put_le16(p + 65, 0x0096);                  /* Min. Multiword DMA cycle */
+    put_le16(p + 66, 0x0096);                  /* Rec. Multiword DMA cycle */
+    put_le16(p + 68, 0x00b4);                  /* Min. PIO cycle time */
+    put_le16(p + 82, 0x400c);                  /* Command Set supported */
+    put_le16(p + 83, 0x7068);                  /* Command Set supported */
+    put_le16(p + 84, 0x4000);                  /* Features supported */
+    put_le16(p + 85, 0x000c);                  /* Command Set enabled */
+    put_le16(p + 86, 0x7044);                  /* Command Set enabled */
+    put_le16(p + 87, 0x4000);                  /* Features enabled */
+    put_le16(p + 91, 0x4060);                  /* Current APM level */
+    put_le16(p + 129, 0x0002);                 /* Current features option */
+    put_le16(p + 130, 0x0005);                 /* Reassigned sectors */
+    put_le16(p + 131, 0x0001);                 /* Initial power mode */
+    put_le16(p + 132, 0x0000);                 /* User signature */
+    put_le16(p + 160, 0x8100);                 /* Power requirement */
+    put_le16(p + 161, 0x8001);                 /* CF command set */
+
+    s->identify_set = 1;
+
+fill_buffer:
+    memcpy(s->io_buffer, p, sizeof(s->identify_data));
+}
+
+static void ide_set_signature(IDEState *s)
+{
+    s->select &= 0xf0; /* clear head */
+    /* put signature */
+    s->nsector = 1;
+    s->sector = 1;
+    if (s->is_cdrom) {
+        s->lcyl = 0x14;
+        s->hcyl = 0xeb;
+    } else if (s->bs) {
+        s->lcyl = 0;
+        s->hcyl = 0;
+    } else {
+        s->lcyl = 0xff;
+        s->hcyl = 0xff;
+    }
+}
+
+static inline void ide_abort_command(IDEState *s)
+{
+    s->status = READY_STAT | ERR_STAT;
+    s->error = ABRT_ERR;
+}
+
+static inline void ide_set_irq(IDEState *s)
+{
+    BMDMAState *bm = s->bmdma;
+    if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) {
+        if (bm) {
+            bm->status |= BM_STATUS_INT;
+        }
+        qemu_irq_raise(s->irq);
+    }
+}
+
+/* prepare data transfer and tell what to do after */
+static void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
+                               EndTransferFunc *end_transfer_func)
+{
+    s->end_transfer_func = end_transfer_func;
+    s->data_ptr = buf;
+    s->data_end = buf + size;
+    if (!(s->status & ERR_STAT))
+        s->status |= DRQ_STAT;
+}
+
+static void ide_transfer_stop(IDEState *s)
+{
+    s->end_transfer_func = ide_transfer_stop;
+    s->data_ptr = s->io_buffer;
+    s->data_end = s->io_buffer;
+    s->status &= ~DRQ_STAT;
+}
+
+static int64_t ide_get_sector(IDEState *s)
+{
+    int64_t sector_num;
+    if (s->select & 0x40) {
+        /* lba */
+       if (!s->lba48) {
+           sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) |
+               (s->lcyl << 8) | s->sector;
+       } else {
+           sector_num = ((int64_t)s->hob_hcyl << 40) |
+               ((int64_t) s->hob_lcyl << 32) |
+               ((int64_t) s->hob_sector << 24) |
+               ((int64_t) s->hcyl << 16) |
+               ((int64_t) s->lcyl << 8) | s->sector;
+       }
+    } else {
+        sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors +
+            (s->select & 0x0f) * s->sectors + (s->sector - 1);
+    }
+    return sector_num;
+}
+
+static void ide_set_sector(IDEState *s, uint64_t sector_num)
+{
+    unsigned int cyl, r;
+    if (s->select & 0x40) {
+       if (!s->lba48) {
+            s->select = (s->select & 0xf0) | (sector_num >> 24);
+            s->hcyl = (sector_num >> 16);
+            s->lcyl = (sector_num >> 8);
+            s->sector = (sector_num);
+       } else {
+           s->sector = sector_num;
+           s->lcyl = sector_num >> 8;
+           s->hcyl = sector_num >> 16;
+           s->hob_sector = sector_num >> 24;
+           s->hob_lcyl = sector_num >> 32;
+           s->hob_hcyl = sector_num >> 40;
+       }
+    } else {
+        cyl = sector_num / (s->heads * s->sectors);
+        r = sector_num % (s->heads * s->sectors);
+        s->hcyl = cyl >> 8;
+        s->lcyl = cyl;
+        s->select = (s->select & 0xf0) | ((r / s->sectors) & 0x0f);
+        s->sector = (r % s->sectors) + 1;
+    }
+}
+
+static void ide_sector_read(IDEState *s)
+{
+    int64_t sector_num;
+    int ret, n;
+
+    s->status = READY_STAT | SEEK_STAT;
+    s->error = 0; /* not needed by IDE spec, but needed by Windows */
+    sector_num = ide_get_sector(s);
+    n = s->nsector;
+    if (n == 0) {
+        /* no more sector to read from disk */
+        ide_transfer_stop(s);
+    } else {
+#if defined(DEBUG_IDE)
+        printf("read sector=%Ld\n", sector_num);
+#endif
+        if (n > s->req_nb_sectors)
+            n = s->req_nb_sectors;
+        ret = bdrv_read(s->bs, sector_num, s->io_buffer, n);
+        ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read);
+        ide_set_irq(s);
+        ide_set_sector(s, sector_num + n);
+        s->nsector -= n;
+    }
+}
+
+/* return 0 if buffer completed */
+static int dma_buf_rw(BMDMAState *bm, int is_write)
+{
+    IDEState *s = bm->ide_if;
+    struct {
+        uint32_t addr;
+        uint32_t size;
+    } prd;
+    int l, len;
+
+    for(;;) {
+        l = s->io_buffer_size - s->io_buffer_index;
+        if (l <= 0)
+            break;
+        if (bm->cur_prd_len == 0) {
+            /* end of table (with a fail safe of one page) */
+            if (bm->cur_prd_last ||
+                (bm->cur_addr - bm->addr) >= 4096)
+                return 0;
+            cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8);
+            bm->cur_addr += 8;
+            prd.addr = le32_to_cpu(prd.addr);
+            prd.size = le32_to_cpu(prd.size);
+            len = prd.size & 0xfffe;
+            if (len == 0)
+                len = 0x10000;
+            bm->cur_prd_len = len;
+            bm->cur_prd_addr = prd.addr;
+            bm->cur_prd_last = (prd.size & 0x80000000);
+        }
+        if (l > bm->cur_prd_len)
+            l = bm->cur_prd_len;
+        if (l > 0) {
+            if (is_write) {
+                cpu_physical_memory_write(bm->cur_prd_addr,
+                                          s->io_buffer + s->io_buffer_index, 
l);
+            } else {
+                cpu_physical_memory_read(bm->cur_prd_addr,
+                                          s->io_buffer + s->io_buffer_index, 
l);
+            }
+            bm->cur_prd_addr += l;
+            bm->cur_prd_len -= l;
+            s->io_buffer_index += l;
+        }
+    }
+    return 1;
+}
+
+/* XXX: handle errors */
+static void ide_read_dma_cb(void *opaque, int ret)
+{
+    BMDMAState *bm = opaque;
+    IDEState *s = bm->ide_if;
+    int n;
+    int64_t sector_num;
+
+    n = s->io_buffer_size >> 9;
+    sector_num = ide_get_sector(s);
+    if (n > 0) {
+        sector_num += n;
+        ide_set_sector(s, sector_num);
+        s->nsector -= n;
+        if (dma_buf_rw(bm, 1) == 0)
+            goto eot;
+    }
+
+    /* end of transfer ? */
+    if (s->nsector == 0) {
+        s->status = READY_STAT | SEEK_STAT;
+        ide_set_irq(s);
+    eot:
+        bm->status &= ~BM_STATUS_DMAING;
+        bm->status |= BM_STATUS_INT;
+        bm->dma_cb = NULL;
+        bm->ide_if = NULL;
+        bm->aiocb = NULL;
+        return;
+    }
+
+    /* launch next transfer */
+    n = s->nsector;
+    if (n > MAX_MULT_SECTORS)
+        n = MAX_MULT_SECTORS;
+    s->io_buffer_index = 0;
+    s->io_buffer_size = n * 512;
+#ifdef DEBUG_AIO
+    printf("aio_read: sector_num=%lld n=%d\n", sector_num, n);
+#endif
+    bm->aiocb = bdrv_aio_read(s->bs, sector_num, s->io_buffer, n,
+                              ide_read_dma_cb, bm);
+}
+
+static void ide_sector_read_dma(IDEState *s)
+{
+    s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
+    s->io_buffer_index = 0;
+    s->io_buffer_size = 0;
+    ide_dma_start(s, ide_read_dma_cb);
+}
+
+#ifdef TARGET_I386
+static void ide_sector_write_timer_cb(void *opaque)
+{
+    IDEState *s = opaque;
+    ide_set_irq(s);
+}
+#endif
+
+static void ide_sector_write(IDEState *s)
+{
+    int64_t sector_num;
+    int ret, n, n1;
+
+    s->status = READY_STAT | SEEK_STAT;
+    sector_num = ide_get_sector(s);
+#if defined(DEBUG_IDE)
+    printf("write sector=%Ld\n", sector_num);
+#endif
+    n = s->nsector;
+    if (n > s->req_nb_sectors)
+        n = s->req_nb_sectors;
+    ret = bdrv_write(s->bs, sector_num, s->io_buffer, n);
+    s->nsector -= n;
+    if (s->nsector == 0) {
+        /* no more sectors to write */
+        ide_transfer_stop(s);
+    } else {
+        n1 = s->nsector;
+        if (n1 > s->req_nb_sectors)
+            n1 = s->req_nb_sectors;
+        ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write);
+    }
+    ide_set_sector(s, sector_num + n);
+
+#ifdef TARGET_I386
+    if (win2k_install_hack && ((++s->irq_count % 16) == 0)) {
+        /* It seems there is a bug in the Windows 2000 installer HDD
+           IDE driver which fills the disk with empty logs when the
+           IDE write IRQ comes too early. This hack tries to correct
+           that at the expense of slower write performances. Use this
+           option _only_ to install Windows 2000. You must disable it
+           for normal use. */
+        qemu_mod_timer(s->sector_write_timer, 
+                       qemu_get_clock(vm_clock) + (ticks_per_sec / 1000));
+    } else 
+#endif
+    {
+        ide_set_irq(s);
+    }
+}
+
+/* XXX: handle errors */
+static void ide_write_dma_cb(void *opaque, int ret)
+{
+    BMDMAState *bm = opaque;
+    IDEState *s = bm->ide_if;
+    int n;
+    int64_t sector_num;
+
+    n = s->io_buffer_size >> 9;
+    sector_num = ide_get_sector(s);
+    if (n > 0) {
+        sector_num += n;
+        ide_set_sector(s, sector_num);
+        s->nsector -= n;
+    }
+
+    /* end of transfer ? */
+    if (s->nsector == 0) {
+        s->status = READY_STAT | SEEK_STAT;
+        ide_set_irq(s);
+    eot:
+        bm->status &= ~BM_STATUS_DMAING;
+        bm->status |= BM_STATUS_INT;
+        bm->dma_cb = NULL;
+        bm->ide_if = NULL;
+        bm->aiocb = NULL;
+        return;
+    }
+
+    /* launch next transfer */
+    n = s->nsector;
+    if (n > MAX_MULT_SECTORS)
+        n = MAX_MULT_SECTORS;
+    s->io_buffer_index = 0;
+    s->io_buffer_size = n * 512;
+
+    if (dma_buf_rw(bm, 0) == 0)
+        goto eot;
+#ifdef DEBUG_AIO
+    printf("aio_write: sector_num=%lld n=%d\n", sector_num, n);
+#endif
+    bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n,
+                               ide_write_dma_cb, bm);
+}
+
+static void ide_sector_write_dma(IDEState *s)
+{
+    s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
+    s->io_buffer_index = 0;
+    s->io_buffer_size = 0;
+    ide_dma_start(s, ide_write_dma_cb);
+}
+
+static void ide_atapi_cmd_ok(IDEState *s)
+{
+    s->error = 0;
+    s->status = READY_STAT;
+    s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
+    ide_set_irq(s);
+}
+
+static void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc)
+{
+#ifdef DEBUG_IDE_ATAPI
+    printf("atapi_cmd_error: sense=0x%x asc=0x%x\n", sense_key, asc);
+#endif
+    s->error = sense_key << 4;
+    s->status = READY_STAT | ERR_STAT;
+    s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
+    s->sense_key = sense_key;
+    s->asc = asc;
+    ide_set_irq(s);
+}
+
+static inline void cpu_to_ube16(uint8_t *buf, int val)
+{
+    buf[0] = val >> 8;
+    buf[1] = val;
+}
+
+static inline void cpu_to_ube32(uint8_t *buf, unsigned int val)
+{
+    buf[0] = val >> 24;
+    buf[1] = val >> 16;
+    buf[2] = val >> 8;
+    buf[3] = val;
+}
+
+static inline int ube16_to_cpu(const uint8_t *buf)
+{
+    return (buf[0] << 8) | buf[1];
+}
+
+static inline int ube32_to_cpu(const uint8_t *buf)
+{
+    return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+}
+
+static void lba_to_msf(uint8_t *buf, int lba)
+{
+    lba += 150;
+    buf[0] = (lba / 75) / 60;
+    buf[1] = (lba / 75) % 60;
+    buf[2] = lba % 75;
+}
+
+static void cd_data_to_raw(uint8_t *buf, int lba)
+{
+    /* sync bytes */
+    buf[0] = 0x00;
+    memset(buf + 1, 0xff, 10);
+    buf[11] = 0x00;
+    buf += 12;
+    /* MSF */
+    lba_to_msf(buf, lba);
+    buf[3] = 0x01; /* mode 1 data */
+    buf += 4;
+    /* data */
+    buf += 2048;
+    /* XXX: ECC not computed */
+    memset(buf, 0, 288);
+}
+
+static int cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf,
+                           int sector_size)
+{
+    int ret;
+
+    switch(sector_size) {
+    case 2048:
+        ret = bdrv_read(bs, (int64_t)lba << 2, buf, 4);
+        break;
+    case 2352:
+        ret = bdrv_read(bs, (int64_t)lba << 2, buf + 16, 4);
+        if (ret < 0)
+            return ret;
+        cd_data_to_raw(buf, lba);
+        break;
+    default:
+        ret = -EIO;
+        break;
+    }
+    return ret;
+}
+
+static void ide_atapi_io_error(IDEState *s, int ret)
+{
+    /* XXX: handle more errors */
+    if (ret == -ENOMEDIUM) {
+        ide_atapi_cmd_error(s, SENSE_NOT_READY,
+                            ASC_MEDIUM_NOT_PRESENT);
+    } else {
+        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                            ASC_LOGICAL_BLOCK_OOR);
+    }
+}
+
+/* The whole ATAPI transfer logic is handled in this function */
+static void ide_atapi_cmd_reply_end(IDEState *s)
+{
+    int byte_count_limit, size, ret;
+#ifdef DEBUG_IDE_ATAPI
+    printf("reply: tx_size=%d elem_tx_size=%d index=%d\n",
+           s->packet_transfer_size,
+           s->elementary_transfer_size,
+           s->io_buffer_index);
+#endif
+    if (s->packet_transfer_size <= 0) {
+        /* end of transfer */
+        ide_transfer_stop(s);
+        s->status = READY_STAT;
+        s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | 
ATAPI_INT_REASON_CD;
+        ide_set_irq(s);
+#ifdef DEBUG_IDE_ATAPI
+        printf("status=0x%x\n", s->status);
+#endif
+    } else {
+        /* see if a new sector must be read */
+        if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) {
+            ret = cd_read_sector(s->bs, s->lba, s->io_buffer, 
s->cd_sector_size);
+            if (ret < 0) {
+                ide_transfer_stop(s);
+                ide_atapi_io_error(s, ret);
+                return;
+            }
+            s->lba++;
+            s->io_buffer_index = 0;
+        }
+        if (s->elementary_transfer_size > 0) {
+            /* there are some data left to transmit in this elementary
+               transfer */
+            size = s->cd_sector_size - s->io_buffer_index;
+            if (size > s->elementary_transfer_size)
+                size = s->elementary_transfer_size;
+            ide_transfer_start(s, s->io_buffer + s->io_buffer_index,
+                               size, ide_atapi_cmd_reply_end);
+            s->packet_transfer_size -= size;
+            s->elementary_transfer_size -= size;
+            s->io_buffer_index += size;
+        } else {
+            /* a new transfer is needed */
+            s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO;
+            byte_count_limit = s->lcyl | (s->hcyl << 8);
+#ifdef DEBUG_IDE_ATAPI
+            printf("byte_count_limit=%d\n", byte_count_limit);
+#endif
+            if (byte_count_limit == 0xffff)
+                byte_count_limit--;
+            size = s->packet_transfer_size;
+            if (size > byte_count_limit) {
+                /* byte count limit must be even if this case */
+                if (byte_count_limit & 1)
+                    byte_count_limit--;
+                size = byte_count_limit;
+            }
+            s->lcyl = size;
+            s->hcyl = size >> 8;
+            s->elementary_transfer_size = size;
+            /* we cannot transmit more than one sector at a time */
+            if (s->lba != -1) {
+                if (size > (s->cd_sector_size - s->io_buffer_index))
+                    size = (s->cd_sector_size - s->io_buffer_index);
+            }
+            ide_transfer_start(s, s->io_buffer + s->io_buffer_index,
+                               size, ide_atapi_cmd_reply_end);
+            s->packet_transfer_size -= size;
+            s->elementary_transfer_size -= size;
+            s->io_buffer_index += size;
+            ide_set_irq(s);
+#ifdef DEBUG_IDE_ATAPI
+            printf("status=0x%x\n", s->status);
+#endif
+        }
+    }
+}
+
+/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */
+static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size)
+{
+    if (size > max_size)
+        size = max_size;
+    s->lba = -1; /* no sector read */
+    s->packet_transfer_size = size;
+    s->io_buffer_size = size;    /* dma: send the reply data as one chunk */
+    s->elementary_transfer_size = 0;
+    s->io_buffer_index = 0;
+
+    if (s->atapi_dma) {
+       s->status = READY_STAT | DRQ_STAT;
+       ide_dma_start(s, ide_atapi_cmd_read_dma_cb);
+    } else {
+       s->status = READY_STAT;
+       ide_atapi_cmd_reply_end(s);
+    }
+}
+
+/* start a CD-CDROM read command */
+static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors,
+                                   int sector_size)
+{
+    s->lba = lba;
+    s->packet_transfer_size = nb_sectors * sector_size;
+    s->elementary_transfer_size = 0;
+    s->io_buffer_index = sector_size;
+    s->cd_sector_size = sector_size;
+
+    s->status = READY_STAT;
+    ide_atapi_cmd_reply_end(s);
+}
+
+/* ATAPI DMA support */
+
+/* XXX: handle read errors */
+static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
+{
+    BMDMAState *bm = opaque;
+    IDEState *s = bm->ide_if;
+    int data_offset, n;
+
+    if (ret < 0) {
+        ide_atapi_io_error(s, ret);
+        goto eot;
+    }
+
+    if (s->io_buffer_size > 0) {
+       /*
+        * For a cdrom read sector command (s->lba != -1),
+        * adjust the lba for the next s->io_buffer_size chunk
+        * and dma the current chunk.
+        * For a command != read (s->lba == -1), just transfer
+        * the reply data.
+        */
+       if (s->lba != -1) {
+           if (s->cd_sector_size == 2352) {
+               n = 1;
+               cd_data_to_raw(s->io_buffer, s->lba);
+           } else {
+               n = s->io_buffer_size >> 11;
+           }
+           s->lba += n;
+       }
+        s->packet_transfer_size -= s->io_buffer_size;
+        if (dma_buf_rw(bm, 1) == 0)
+            goto eot;
+    }
+
+    if (s->packet_transfer_size <= 0) {
+        s->status = READY_STAT;
+        s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | 
ATAPI_INT_REASON_CD;
+        ide_set_irq(s);
+    eot:
+        bm->status &= ~BM_STATUS_DMAING;
+        bm->status |= BM_STATUS_INT;
+        bm->dma_cb = NULL;
+        bm->ide_if = NULL;
+        bm->aiocb = NULL;
+        return;
+    }
+
+    s->io_buffer_index = 0;
+    if (s->cd_sector_size == 2352) {
+        n = 1;
+        s->io_buffer_size = s->cd_sector_size;
+        data_offset = 16;
+    } else {
+        n = s->packet_transfer_size >> 11;
+        if (n > (MAX_MULT_SECTORS / 4))
+            n = (MAX_MULT_SECTORS / 4);
+        s->io_buffer_size = n * 2048;
+        data_offset = 0;
+    }
+#ifdef DEBUG_AIO
+    printf("aio_read_cd: lba=%u n=%d\n", s->lba, n);
+#endif
+    bm->aiocb = bdrv_aio_read(s->bs, (int64_t)s->lba << 2,
+                              s->io_buffer + data_offset, n * 4,
+                              ide_atapi_cmd_read_dma_cb, bm);
+    if (!bm->aiocb) {
+        /* Note: media not present is the most likely case */
+        ide_atapi_cmd_error(s, SENSE_NOT_READY,
+                            ASC_MEDIUM_NOT_PRESENT);
+        goto eot;
+    }
+}
+
+/* start a CD-CDROM read command with DMA */
+/* XXX: test if DMA is available */
+static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors,
+                                   int sector_size)
+{
+    s->lba = lba;
+    s->packet_transfer_size = nb_sectors * sector_size;
+    s->io_buffer_index = 0;
+    s->io_buffer_size = 0;
+    s->cd_sector_size = sector_size;
+
+    /* XXX: check if BUSY_STAT should be set */
+    s->status = READY_STAT | DRQ_STAT | BUSY_STAT;
+    ide_dma_start(s, ide_atapi_cmd_read_dma_cb);
+}
+
+static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors,
+                               int sector_size)
+{
+#ifdef DEBUG_IDE_ATAPI
+    printf("read %s: LBA=%d nb_sectors=%d\n", s->atapi_dma ? "dma" : "pio",
+       lba, nb_sectors);
+#endif
+    if (s->atapi_dma) {
+        ide_atapi_cmd_read_dma(s, lba, nb_sectors, sector_size);
+    } else {
+        ide_atapi_cmd_read_pio(s, lba, nb_sectors, sector_size);
+    }
+}
+
+static void ide_atapi_cmd(IDEState *s)
+{
+    const uint8_t *packet;
+    uint8_t *buf;
+    int max_len;
+
+    packet = s->io_buffer;
+    buf = s->io_buffer;
+#ifdef DEBUG_IDE_ATAPI
+    {
+        int i;
+        printf("ATAPI limit=0x%x packet:", s->lcyl | (s->hcyl << 8));
+        for(i = 0; i < ATAPI_PACKET_SIZE; i++) {
+            printf(" %02x", packet[i]);
+        }
+        printf("\n");
+    }
+#endif
+    switch(s->io_buffer[0]) {
+    case GPCMD_TEST_UNIT_READY:
+        if (bdrv_is_inserted(s->bs)) {
+            ide_atapi_cmd_ok(s);
+        } else {
+            ide_atapi_cmd_error(s, SENSE_NOT_READY,
+                                ASC_MEDIUM_NOT_PRESENT);
+        }
+        break;
+    case GPCMD_MODE_SENSE_6:
+    case GPCMD_MODE_SENSE_10:
+        {
+            int action, code;
+            if (packet[0] == GPCMD_MODE_SENSE_10)
+                max_len = ube16_to_cpu(packet + 7);
+            else
+                max_len = packet[4];
+            action = packet[2] >> 6;
+            code = packet[2] & 0x3f;
+            switch(action) {
+            case 0: /* current values */
+                switch(code) {
+                case 0x01: /* error recovery */
+                    cpu_to_ube16(&buf[0], 16 + 6);
+                    buf[2] = 0x70;
+                    buf[3] = 0;
+                    buf[4] = 0;
+                    buf[5] = 0;
+                    buf[6] = 0;
+                    buf[7] = 0;
+
+                    buf[8] = 0x01;
+                    buf[9] = 0x06;
+                    buf[10] = 0x00;
+                    buf[11] = 0x05;
+                    buf[12] = 0x00;
+                    buf[13] = 0x00;
+                    buf[14] = 0x00;
+                    buf[15] = 0x00;
+                    ide_atapi_cmd_reply(s, 16, max_len);
+                    break;
+                case 0x2a:
+                    cpu_to_ube16(&buf[0], 28 + 6);
+                    buf[2] = 0x70;
+                    buf[3] = 0;
+                    buf[4] = 0;
+                    buf[5] = 0;
+                    buf[6] = 0;
+                    buf[7] = 0;
+
+                    buf[8] = 0x2a;
+                    buf[9] = 0x12;
+                    buf[10] = 0x08;
+                    buf[11] = 0x00;
+
+                    buf[12] = 0x70;
+                    buf[13] = 3 << 5;
+                    buf[14] = (1 << 0) | (1 << 3) | (1 << 5);
+                    if (bdrv_is_locked(s->bs))
+                        buf[6] |= 1 << 1;
+                    buf[15] = 0x00;
+                    cpu_to_ube16(&buf[16], 706);
+                    buf[18] = 0;
+                    buf[19] = 2;
+                    cpu_to_ube16(&buf[20], 512);
+                    cpu_to_ube16(&buf[22], 706);
+                    buf[24] = 0;
+                    buf[25] = 0;
+                    buf[26] = 0;
+                    buf[27] = 0;
+                    ide_atapi_cmd_reply(s, 28, max_len);
+                    break;
+                default:
+                    goto error_cmd;
+                }
+                break;
+            case 1: /* changeable values */
+                goto error_cmd;
+            case 2: /* default values */
+                goto error_cmd;
+            default:
+            case 3: /* saved values */
+                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                    ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
+                break;
+            }
+        }
+        break;
+    case GPCMD_REQUEST_SENSE:
+        max_len = packet[4];
+        memset(buf, 0, 18);
+        buf[0] = 0x70 | (1 << 7);
+        buf[2] = s->sense_key;
+        buf[7] = 10;
+        buf[12] = s->asc;
+        ide_atapi_cmd_reply(s, 18, max_len);
+        break;
+    case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
+        if (bdrv_is_inserted(s->bs)) {
+            bdrv_set_locked(s->bs, packet[4] & 1);
+            ide_atapi_cmd_ok(s);
+        } else {
+            ide_atapi_cmd_error(s, SENSE_NOT_READY,
+                                ASC_MEDIUM_NOT_PRESENT);
+        }
+        break;
+    case GPCMD_READ_10:
+    case GPCMD_READ_12:
+        {
+            int nb_sectors, lba;
+
+            if (packet[0] == GPCMD_READ_10)
+                nb_sectors = ube16_to_cpu(packet + 7);
+            else
+                nb_sectors = ube32_to_cpu(packet + 6);
+            lba = ube32_to_cpu(packet + 2);
+            if (nb_sectors == 0) {
+                ide_atapi_cmd_ok(s);
+                break;
+            }
+            ide_atapi_cmd_read(s, lba, nb_sectors, 2048);
+        }
+        break;
+    case GPCMD_READ_CD:
+        {
+            int nb_sectors, lba, transfer_request;
+
+            nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8];
+            lba = ube32_to_cpu(packet + 2);
+            if (nb_sectors == 0) {
+                ide_atapi_cmd_ok(s);
+                break;
+            }
+            transfer_request = packet[9];
+            switch(transfer_request & 0xf8) {
+            case 0x00:
+                /* nothing */
+                ide_atapi_cmd_ok(s);
+                break;
+            case 0x10:
+                /* normal read */
+                ide_atapi_cmd_read(s, lba, nb_sectors, 2048);
+                break;
+            case 0xf8:
+                /* read all data */
+                ide_atapi_cmd_read(s, lba, nb_sectors, 2352);
+                break;
+            default:
+                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                    ASC_INV_FIELD_IN_CMD_PACKET);
+                break;
+            }
+        }
+        break;
+    case GPCMD_SEEK:
+        {
+            int lba;
+            int64_t total_sectors;
+
+            bdrv_get_geometry(s->bs, &total_sectors);
+            total_sectors >>= 2;
+            if (total_sectors <= 0) {
+                ide_atapi_cmd_error(s, SENSE_NOT_READY,
+                                    ASC_MEDIUM_NOT_PRESENT);
+                break;
+            }
+            lba = ube32_to_cpu(packet + 2);
+            if (lba >= total_sectors) {
+                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                    ASC_LOGICAL_BLOCK_OOR);
+                break;
+            }
+            ide_atapi_cmd_ok(s);
+        }
+        break;
+    case GPCMD_START_STOP_UNIT:
+        {
+            int start, eject;
+            start = packet[4] & 1;
+            eject = (packet[4] >> 1) & 1;
+
+            if (eject && !start) {
+                /* eject the disk */
+                bdrv_eject(s->bs, 1);
+            } else if (eject && start) {
+                /* close the tray */
+                bdrv_eject(s->bs, 0);
+            }
+            ide_atapi_cmd_ok(s);
+        }
+        break;
+    case GPCMD_MECHANISM_STATUS:
+        {
+            max_len = ube16_to_cpu(packet + 8);
+            cpu_to_ube16(buf, 0);
+            /* no current LBA */
+            buf[2] = 0;
+            buf[3] = 0;
+            buf[4] = 0;
+            buf[5] = 1;
+            cpu_to_ube16(buf + 6, 0);
+            ide_atapi_cmd_reply(s, 8, max_len);
+        }
+        break;
+    case GPCMD_READ_TOC_PMA_ATIP:
+        {
+            int format, msf, start_track, len;
+            int64_t total_sectors;
+
+            bdrv_get_geometry(s->bs, &total_sectors);
+            total_sectors >>= 2;
+            if (total_sectors <= 0) {
+                ide_atapi_cmd_error(s, SENSE_NOT_READY,
+                                    ASC_MEDIUM_NOT_PRESENT);
+                break;
+            }
+            max_len = ube16_to_cpu(packet + 7);
+            format = packet[9] >> 6;
+            msf = (packet[1] >> 1) & 1;
+            start_track = packet[6];
+            switch(format) {
+            case 0:
+                len = cdrom_read_toc(total_sectors, buf, msf, start_track);
+                if (len < 0)
+                    goto error_cmd;
+                ide_atapi_cmd_reply(s, len, max_len);
+                break;
+            case 1:
+                /* multi session : only a single session defined */
+                memset(buf, 0, 12);
+                buf[1] = 0x0a;
+                buf[2] = 0x01;
+                buf[3] = 0x01;
+                ide_atapi_cmd_reply(s, 12, max_len);
+                break;
+            case 2:
+                len = cdrom_read_toc_raw(total_sectors, buf, msf, start_track);
+                if (len < 0)
+                    goto error_cmd;
+                ide_atapi_cmd_reply(s, len, max_len);
+                break;
+            default:
+            error_cmd:
+                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                    ASC_INV_FIELD_IN_CMD_PACKET);
+                break;
+            }
+        }
+        break;
+    case GPCMD_READ_CDVD_CAPACITY:
+        {
+            int64_t total_sectors;
+
+            bdrv_get_geometry(s->bs, &total_sectors);
+            total_sectors >>= 2;
+            if (total_sectors <= 0) {
+                ide_atapi_cmd_error(s, SENSE_NOT_READY,
+                                    ASC_MEDIUM_NOT_PRESENT);
+                break;
+            }
+            /* NOTE: it is really the number of sectors minus 1 */
+            cpu_to_ube32(buf, total_sectors - 1);
+            cpu_to_ube32(buf + 4, 2048);
+            ide_atapi_cmd_reply(s, 8, 8);
+        }
+        break;
+    case GPCMD_READ_DVD_STRUCTURE:
+        {
+            int media = packet[1];
+            int layer = packet[6];
+            int format = packet[2];
+            int64_t total_sectors;
+
+            if (media != 0 || layer != 0)
+            {
+                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                    ASC_INV_FIELD_IN_CMD_PACKET);
+            }
+
+            switch (format) {
+                case 0:
+                    bdrv_get_geometry(s->bs, &total_sectors);
+                    total_sectors >>= 2;
+
+                    memset(buf, 0, 2052);
+
+                    buf[4] = 1;   // DVD-ROM, part version 1
+                    buf[5] = 0xf; // 120mm disc, maximum rate unspecified
+                    buf[6] = 0;   // one layer, embossed data
+                    buf[7] = 0;
+
+                    cpu_to_ube32(buf + 8, 0);
+                    cpu_to_ube32(buf + 12, total_sectors - 1);
+                    cpu_to_ube32(buf + 16, total_sectors - 1);
+
+                    cpu_to_be16wu((uint16_t *)buf, 2048 + 4);
+
+                    ide_atapi_cmd_reply(s, 2048 + 3, 2048 + 4);
+                    break;
+
+                default:
+                    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                        ASC_INV_FIELD_IN_CMD_PACKET);
+                    break;
+            }
+        }
+        break;
+    case GPCMD_SET_SPEED:
+        ide_atapi_cmd_ok(s);
+        break;
+    case GPCMD_INQUIRY:
+        max_len = packet[4];
+        buf[0] = 0x05; /* CD-ROM */
+        buf[1] = 0x80; /* removable */
+        buf[2] = 0x00; /* ISO */
+        buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
+        buf[4] = 31; /* additional length */
+        buf[5] = 0; /* reserved */
+        buf[6] = 0; /* reserved */
+        buf[7] = 0; /* reserved */
+        padstr8(buf + 8, 8, "QEMU");
+        padstr8(buf + 16, 16, "QEMU CD-ROM");
+        padstr8(buf + 32, 4, QEMU_VERSION);
+        ide_atapi_cmd_reply(s, 36, max_len);
+        break;
+    case GPCMD_GET_CONFIGURATION:
+        {
+            int64_t total_sectors;
+
+            /* only feature 0 is supported */
+            if (packet[2] != 0 || packet[3] != 0) {
+                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                    ASC_INV_FIELD_IN_CMD_PACKET);
+                break;
+            }
+            memset(buf, 0, 32);
+            bdrv_get_geometry(s->bs, &total_sectors);
+            buf[3] = 16;
+            buf[7] = total_sectors <= 1433600 ? 0x08 : 0x10; /* current 
profile */
+            buf[10] = 0x10 | 0x1;
+            buf[11] = 0x08; /* size of profile list */
+            buf[13] = 0x10; /* DVD-ROM profile */
+            buf[14] = buf[7] == 0x10; /* (in)active */
+            buf[17] = 0x08; /* CD-ROM profile */
+            buf[18] = buf[7] == 0x08; /* (in)active */
+            ide_atapi_cmd_reply(s, 32, 32);
+            break;
+        }
+    default:
+        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                            ASC_ILLEGAL_OPCODE);
+        break;
+    }
+}
+
+static void ide_cfata_metadata_inquiry(IDEState *s)
+{
+    uint16_t *p;
+    uint32_t spd;
+
+    p = (uint16_t *) s->io_buffer;
+    memset(p, 0, 0x200);
+    spd = ((s->mdata_size - 1) >> 9) + 1;
+
+    put_le16(p + 0, 0x0001);                   /* Data format revision */
+    put_le16(p + 1, 0x0000);                   /* Media property: silicon */
+    put_le16(p + 2, s->media_changed);         /* Media status */
+    put_le16(p + 3, s->mdata_size & 0xffff);   /* Capacity in bytes (low) */
+    put_le16(p + 4, s->mdata_size >> 16);      /* Capacity in bytes (high) */
+    put_le16(p + 5, spd & 0xffff);             /* Sectors per device (low) */
+    put_le16(p + 6, spd >> 16);                        /* Sectors per device 
(high) */
+}
+
+static void ide_cfata_metadata_read(IDEState *s)
+{
+    uint16_t *p;
+
+    if (((s->hcyl << 16) | s->lcyl) << 9 > s->mdata_size + 2) {
+        s->status = ERR_STAT;
+        s->error = ABRT_ERR;
+        return;
+    }
+
+    p = (uint16_t *) s->io_buffer;
+    memset(p, 0, 0x200);
+
+    put_le16(p + 0, s->media_changed);         /* Media status */
+    memcpy(p + 1, s->mdata_storage + (((s->hcyl << 16) | s->lcyl) << 9),
+                    MIN(MIN(s->mdata_size - (((s->hcyl << 16) | s->lcyl) << 9),
+                                    s->nsector << 9), 0x200 - 2));
+}
+
+static void ide_cfata_metadata_write(IDEState *s)
+{
+    if (((s->hcyl << 16) | s->lcyl) << 9 > s->mdata_size + 2) {
+        s->status = ERR_STAT;
+        s->error = ABRT_ERR;
+        return;
+    }
+
+    s->media_changed = 0;
+
+    memcpy(s->mdata_storage + (((s->hcyl << 16) | s->lcyl) << 9),
+                    s->io_buffer + 2,
+                    MIN(MIN(s->mdata_size - (((s->hcyl << 16) | s->lcyl) << 9),
+                                    s->nsector << 9), 0x200 - 2));
+}
+
+/* called when the inserted state of the media has changed */
+static void cdrom_change_cb(void *opaque)
+{
+    IDEState *s = opaque;
+    int64_t nb_sectors;
+
+    /* XXX: send interrupt too */
+    bdrv_get_geometry(s->bs, &nb_sectors);
+    s->nb_sectors = nb_sectors;
+}
+
+static void ide_cmd_lba48_transform(IDEState *s, int lba48)
+{
+    s->lba48 = lba48;
+
+    /* handle the 'magic' 0 nsector count conversion here. to avoid
+     * fiddling with the rest of the read logic, we just store the
+     * full sector count in ->nsector and ignore ->hob_nsector from now
+     */
+    if (!s->lba48) {
+       if (!s->nsector)
+           s->nsector = 256;
+    } else {
+       if (!s->nsector && !s->hob_nsector)
+           s->nsector = 65536;
+       else {
+           int lo = s->nsector;
+           int hi = s->hob_nsector;
+
+           s->nsector = (hi << 8) | lo;
+       }
+    }
+}
+
+static void ide_clear_hob(IDEState *ide_if)
+{
+    /* any write clears HOB high bit of device control register */
+    ide_if[0].select &= ~(1 << 7);
+    ide_if[1].select &= ~(1 << 7);
+}
+
+static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    IDEState *ide_if = opaque;
+    IDEState *s;
+    int unit, n;
+    int lba48 = 0;
+
+#ifdef DEBUG_IDE
+    printf("IDE: write addr=0x%x val=0x%02x\n", addr, val);
+#endif
+
+    addr &= 7;
+    switch(addr) {
+    case 0:
+        break;
+    case 1:
+       ide_clear_hob(ide_if);
+        /* NOTE: data is written to the two drives */
+       ide_if[0].hob_feature = ide_if[0].feature;
+       ide_if[1].hob_feature = ide_if[1].feature;
+        ide_if[0].feature = val;
+        ide_if[1].feature = val;
+        break;
+    case 2:
+       ide_clear_hob(ide_if);
+       ide_if[0].hob_nsector = ide_if[0].nsector;
+       ide_if[1].hob_nsector = ide_if[1].nsector;
+        ide_if[0].nsector = val;
+        ide_if[1].nsector = val;
+        break;
+    case 3:
+       ide_clear_hob(ide_if);
+       ide_if[0].hob_sector = ide_if[0].sector;
+       ide_if[1].hob_sector = ide_if[1].sector;
+        ide_if[0].sector = val;
+        ide_if[1].sector = val;
+        break;
+    case 4:
+       ide_clear_hob(ide_if);
+       ide_if[0].hob_lcyl = ide_if[0].lcyl;
+       ide_if[1].hob_lcyl = ide_if[1].lcyl;
+        ide_if[0].lcyl = val;
+        ide_if[1].lcyl = val;
+        break;
+    case 5:
+       ide_clear_hob(ide_if);
+       ide_if[0].hob_hcyl = ide_if[0].hcyl;
+       ide_if[1].hob_hcyl = ide_if[1].hcyl;
+        ide_if[0].hcyl = val;
+        ide_if[1].hcyl = val;
+        break;
+    case 6:
+       /* FIXME: HOB readback uses bit 7 */
+        ide_if[0].select = (val & ~0x10) | 0xa0;
+        ide_if[1].select = (val | 0x10) | 0xa0;
+        /* select drive */
+        unit = (val >> 4) & 1;
+        s = ide_if + unit;
+        ide_if->cur_drive = s;
+        break;
+    default:
+    case 7:
+        /* command */
+#if defined(DEBUG_IDE)
+        printf("ide: CMD=%02x\n", val);
+#endif
+        s = ide_if->cur_drive;
+        /* ignore commands to non existant slave */
+        if (s != ide_if && !s->bs)
+            break;
+
+        switch(val) {
+        case WIN_IDENTIFY:
+            if (s->bs && !s->is_cdrom) {
+                if (!s->is_cf)
+                    ide_identify(s);
+                else
+                    ide_cfata_identify(s);
+                s->status = READY_STAT | SEEK_STAT;
+                ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
+            } else {
+                if (s->is_cdrom) {
+                    ide_set_signature(s);
+                }
+                ide_abort_command(s);
+            }
+            ide_set_irq(s);
+            break;
+        case WIN_SPECIFY:
+        case WIN_RECAL:
+            s->error = 0;
+            s->status = READY_STAT | SEEK_STAT;
+            ide_set_irq(s);
+            break;
+        case WIN_SETMULT:
+            if (s->is_cf && s->nsector == 0) {
+                /* Disable Read and Write Multiple */
+                s->mult_sectors = 0;
+                s->status = READY_STAT;
+            } else if ((s->nsector & 0xff) != 0 &&
+                ((s->nsector & 0xff) > MAX_MULT_SECTORS ||
+                 (s->nsector & (s->nsector - 1)) != 0)) {
+                ide_abort_command(s);
+            } else {
+                s->mult_sectors = s->nsector & 0xff;
+                s->status = READY_STAT;
+            }
+            ide_set_irq(s);
+            break;
+        case WIN_VERIFY_EXT:
+           lba48 = 1;
+        case WIN_VERIFY:
+        case WIN_VERIFY_ONCE:
+            /* do sector number check ? */
+           ide_cmd_lba48_transform(s, lba48);
+            s->status = READY_STAT;
+            ide_set_irq(s);
+            break;
+       case WIN_READ_EXT:
+           lba48 = 1;
+        case WIN_READ:
+        case WIN_READ_ONCE:
+            if (!s->bs)
+                goto abort_cmd;
+           ide_cmd_lba48_transform(s, lba48);
+            s->req_nb_sectors = 1;
+            ide_sector_read(s);
+            break;
+       case WIN_WRITE_EXT:
+           lba48 = 1;
+        case WIN_WRITE:
+        case WIN_WRITE_ONCE:
+        case CFA_WRITE_SECT_WO_ERASE:
+        case WIN_WRITE_VERIFY:
+           ide_cmd_lba48_transform(s, lba48);
+            s->error = 0;
+            s->status = SEEK_STAT | READY_STAT;
+            s->req_nb_sectors = 1;
+            ide_transfer_start(s, s->io_buffer, 512, ide_sector_write);
+            s->media_changed = 1;
+            break;
+       case WIN_MULTREAD_EXT:
+           lba48 = 1;
+        case WIN_MULTREAD:
+            if (!s->mult_sectors)
+                goto abort_cmd;
+           ide_cmd_lba48_transform(s, lba48);
+            s->req_nb_sectors = s->mult_sectors;
+            ide_sector_read(s);
+            break;
+        case WIN_MULTWRITE_EXT:
+           lba48 = 1;
+        case WIN_MULTWRITE:
+        case CFA_WRITE_MULTI_WO_ERASE:
+            if (!s->mult_sectors)
+                goto abort_cmd;
+           ide_cmd_lba48_transform(s, lba48);
+            s->error = 0;
+            s->status = SEEK_STAT | READY_STAT;
+            s->req_nb_sectors = s->mult_sectors;
+            n = s->nsector;
+            if (n > s->req_nb_sectors)
+                n = s->req_nb_sectors;
+            ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write);
+            s->media_changed = 1;
+            break;
+       case WIN_READDMA_EXT:
+           lba48 = 1;
+        case WIN_READDMA:
+        case WIN_READDMA_ONCE:
+            if (!s->bs)
+                goto abort_cmd;
+           ide_cmd_lba48_transform(s, lba48);
+            ide_sector_read_dma(s);
+            break;
+       case WIN_WRITEDMA_EXT:
+           lba48 = 1;
+        case WIN_WRITEDMA:
+        case WIN_WRITEDMA_ONCE:
+            if (!s->bs)
+                goto abort_cmd;
+           ide_cmd_lba48_transform(s, lba48);
+            ide_sector_write_dma(s);
+            s->media_changed = 1;
+            break;
+        case WIN_READ_NATIVE_MAX_EXT:
+           lba48 = 1;
+        case WIN_READ_NATIVE_MAX:
+           ide_cmd_lba48_transform(s, lba48);
+            ide_set_sector(s, s->nb_sectors - 1);
+            s->status = READY_STAT;
+            ide_set_irq(s);
+            break;
+        case WIN_CHECKPOWERMODE1:
+        case WIN_CHECKPOWERMODE2:
+            s->nsector = 0xff; /* device active or idle */
+            s->status = READY_STAT;
+            ide_set_irq(s);
+            break;
+        case WIN_SETFEATURES:
+            if (!s->bs)
+                goto abort_cmd;
+            /* XXX: valid for CDROM ? */
+            switch(s->feature) {
+            case 0xcc: /* reverting to power-on defaults enable */
+            case 0x66: /* reverting to power-on defaults disable */
+            case 0x02: /* write cache enable */
+            case 0x82: /* write cache disable */
+            case 0xaa: /* read look-ahead enable */
+            case 0x55: /* read look-ahead disable */
+            case 0x05: /* set advanced power management mode */
+            case 0x85: /* disable advanced power management mode */
+            case 0x69: /* NOP */
+            case 0x67: /* NOP */
+            case 0x96: /* NOP */
+            case 0x9a: /* NOP */
+            case 0x42: /* enable Automatic Acoustic Mode */
+            case 0xc2: /* disable Automatic Acoustic Mode */
+                s->status = READY_STAT | SEEK_STAT;
+                ide_set_irq(s);
+                break;
+            case 0x03: { /* set transfer mode */
+               uint8_t val = s->nsector & 0x07;
+
+               switch (s->nsector >> 3) {
+                   case 0x00: /* pio default */
+                   case 0x01: /* pio mode */
+                       put_le16(s->identify_data + 63,0x07);
+                       put_le16(s->identify_data + 88,0x3f);
+                       break;
+                   case 0x04: /* mdma mode */
+                       put_le16(s->identify_data + 63,0x07 | (1 << (val + 8)));
+                       put_le16(s->identify_data + 88,0x3f);
+                       break;
+                   case 0x08: /* udma mode */
+                       put_le16(s->identify_data + 63,0x07);
+                       put_le16(s->identify_data + 88,0x3f | (1 << (val + 8)));
+                       break;
+                   default:
+                       goto abort_cmd;
+               }
+                s->status = READY_STAT | SEEK_STAT;
+                ide_set_irq(s);
+                break;
+           }
+            default:
+                goto abort_cmd;
+            }
+            break;
+        case WIN_FLUSH_CACHE:
+        case WIN_FLUSH_CACHE_EXT:
+            if (s->bs)
+                bdrv_flush(s->bs);
+           s->status = READY_STAT;
+            ide_set_irq(s);
+            break;
+        case WIN_STANDBY:
+        case WIN_STANDBY2:
+        case WIN_STANDBYNOW1:
+        case WIN_STANDBYNOW2:
+        case WIN_IDLEIMMEDIATE:
+        case CFA_IDLEIMMEDIATE:
+        case WIN_SETIDLE1:
+        case WIN_SETIDLE2:
+        case WIN_SLEEPNOW1:
+        case WIN_SLEEPNOW2:
+            s->status = READY_STAT;
+            ide_set_irq(s);
+            break;
+            /* ATAPI commands */
+        case WIN_PIDENTIFY:
+            if (s->is_cdrom) {
+                ide_atapi_identify(s);
+                s->status = READY_STAT | SEEK_STAT;
+                ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
+            } else {
+                ide_abort_command(s);
+            }
+            ide_set_irq(s);
+            break;
+        case WIN_DIAGNOSE:
+            ide_set_signature(s);
+            s->status = 0x00; /* NOTE: READY is _not_ set */
+            s->error = 0x01;
+            break;
+        case WIN_SRST:
+            if (!s->is_cdrom)
+                goto abort_cmd;
+            ide_set_signature(s);
+            s->status = 0x00; /* NOTE: READY is _not_ set */
+            s->error = 0x01;
+            break;
+        case WIN_PACKETCMD:
+            if (!s->is_cdrom)
+                goto abort_cmd;
+            /* overlapping commands not supported */
+            if (s->feature & 0x02)
+                goto abort_cmd;
+            s->status = READY_STAT;
+            s->atapi_dma = s->feature & 1;
+            s->nsector = 1;
+            ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,
+                               ide_atapi_cmd);
+            break;
+        /* CF-ATA commands */
+        case CFA_REQ_EXT_ERROR_CODE:
+            if (!s->is_cf)
+                goto abort_cmd;
+            s->error = 0x09;    /* miscellaneous error */
+            s->status = READY_STAT;
+            ide_set_irq(s);
+            break;
+        case CFA_ERASE_SECTORS:
+        case CFA_WEAR_LEVEL:
+            if (!s->is_cf)
+                goto abort_cmd;
+            if (val == CFA_WEAR_LEVEL)
+                s->nsector = 0;
+            if (val == CFA_ERASE_SECTORS)
+                s->media_changed = 1;
+            s->error = 0x00;
+            s->status = READY_STAT;
+            ide_set_irq(s);
+            break;
+        case CFA_TRANSLATE_SECTOR:
+            if (!s->is_cf)
+                goto abort_cmd;
+            s->error = 0x00;
+            s->status = READY_STAT;
+            memset(s->io_buffer, 0, 0x200);
+            s->io_buffer[0x00] = s->hcyl;                      /* Cyl MSB */
+            s->io_buffer[0x01] = s->lcyl;                      /* Cyl LSB */
+            s->io_buffer[0x02] = s->select;                    /* Head */
+            s->io_buffer[0x03] = s->sector;                    /* Sector */
+            s->io_buffer[0x04] = ide_get_sector(s) >> 16;      /* LBA MSB */
+            s->io_buffer[0x05] = ide_get_sector(s) >> 8;       /* LBA */
+            s->io_buffer[0x06] = ide_get_sector(s) >> 0;       /* LBA LSB */
+            s->io_buffer[0x13] = 0x00;                         /* Erase flag */
+            s->io_buffer[0x18] = 0x00;                         /* Hot count */
+            s->io_buffer[0x19] = 0x00;                         /* Hot count */
+            s->io_buffer[0x1a] = 0x01;                         /* Hot count */
+            ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
+            ide_set_irq(s);
+            break;
+        case CFA_ACCESS_METADATA_STORAGE:
+            if (!s->is_cf)
+                goto abort_cmd;
+            switch (s->feature) {
+            case 0x02: /* Inquiry Metadata Storage */
+                ide_cfata_metadata_inquiry(s);
+                break;
+            case 0x03: /* Read Metadata Storage */
+                ide_cfata_metadata_read(s);
+                break;
+            case 0x04: /* Write Metadata Storage */
+                ide_cfata_metadata_write(s);
+                break;
+            default:
+                goto abort_cmd;
+            }
+            ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
+            s->status = 0x00; /* NOTE: READY is _not_ set */
+            ide_set_irq(s);
+            break;
+        case IBM_SENSE_CONDITION:
+            if (!s->is_cf)
+                goto abort_cmd;
+            switch (s->feature) {
+            case 0x01:  /* sense temperature in device */
+                s->nsector = 0x50;      /* +20 C */
+                break;
+            default:
+                goto abort_cmd;
+            }
+            s->status = READY_STAT;
+            ide_set_irq(s);
+            break;
+        default:
+        abort_cmd:
+            ide_abort_command(s);
+            ide_set_irq(s);
+            break;
+        }
+    }
+}
+
+static uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
+{
+    IDEState *ide_if = opaque;
+    IDEState *s = ide_if->cur_drive;
+    uint32_t addr;
+    int ret, hob;
+
+    addr = addr1 & 7;
+    /* FIXME: HOB readback uses bit 7, but it's always set right now */
+    //hob = s->select & (1 << 7);
+    hob = 0;
+    switch(addr) {
+    case 0:
+        ret = 0xff;
+        break;
+    case 1:
+        if (!ide_if[0].bs && !ide_if[1].bs)
+            ret = 0;
+        else if (!hob)
+            ret = s->error;
+       else
+           ret = s->hob_feature;
+        break;
+    case 2:
+        if (!ide_if[0].bs && !ide_if[1].bs)
+            ret = 0;
+        else if (!hob)
+            ret = s->nsector & 0xff;
+       else
+           ret = s->hob_nsector;
+        break;
+    case 3:
+        if (!ide_if[0].bs && !ide_if[1].bs)
+            ret = 0;
+        else if (!hob)
+            ret = s->sector;
+       else
+           ret = s->hob_sector;
+        break;
+    case 4:
+        if (!ide_if[0].bs && !ide_if[1].bs)
+            ret = 0;
+        else if (!hob)
+            ret = s->lcyl;
+       else
+           ret = s->hob_lcyl;
+        break;
+    case 5:
+        if (!ide_if[0].bs && !ide_if[1].bs)
+            ret = 0;
+        else if (!hob)
+            ret = s->hcyl;
+       else
+           ret = s->hob_hcyl;
+        break;
+    case 6:
+        if (!ide_if[0].bs && !ide_if[1].bs)
+            ret = 0;
+        else
+            ret = s->select;
+        break;
+    default:
+    case 7:
+        if ((!ide_if[0].bs && !ide_if[1].bs) ||
+            (s != ide_if && !s->bs))
+            ret = 0;
+        else
+            ret = s->status;
+        qemu_irq_lower(s->irq);
+        break;
+    }
+#ifdef DEBUG_IDE
+    printf("ide: read addr=0x%x val=%02x\n", addr1, ret);
+#endif
+    return ret;
+}
+
+static uint32_t ide_status_read(void *opaque, uint32_t addr)
+{
+    IDEState *ide_if = opaque;
+    IDEState *s = ide_if->cur_drive;
+    int ret;
+
+    if ((!ide_if[0].bs && !ide_if[1].bs) ||
+        (s != ide_if && !s->bs))
+        ret = 0;
+    else
+        ret = s->status;
+#ifdef DEBUG_IDE
+    printf("ide: read status addr=0x%x val=%02x\n", addr, ret);
+#endif
+    return ret;
+}
+
+static void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    IDEState *ide_if = opaque;
+    IDEState *s;
+    int i;
+
+#ifdef DEBUG_IDE
+    printf("ide: write control addr=0x%x val=%02x\n", addr, val);
+#endif
+    /* common for both drives */
+    if (!(ide_if[0].cmd & IDE_CMD_RESET) &&
+        (val & IDE_CMD_RESET)) {
+        /* reset low to high */
+        for(i = 0;i < 2; i++) {
+            s = &ide_if[i];
+            s->status = BUSY_STAT | SEEK_STAT;
+            s->error = 0x01;
+        }
+    } else if ((ide_if[0].cmd & IDE_CMD_RESET) &&
+               !(val & IDE_CMD_RESET)) {
+        /* high to low */
+        for(i = 0;i < 2; i++) {
+            s = &ide_if[i];
+            if (s->is_cdrom)
+                s->status = 0x00; /* NOTE: READY is _not_ set */
+            else
+                s->status = READY_STAT | SEEK_STAT;
+            ide_set_signature(s);
+        }
+    }
+
+    ide_if[0].cmd = val;
+    ide_if[1].cmd = val;
+}
+
+static void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    IDEState *s = ((IDEState *)opaque)->cur_drive;
+    uint8_t *p;
+
+    p = s->data_ptr;
+    *(uint16_t *)p = le16_to_cpu(val);
+    p += 2;
+    s->data_ptr = p;
+    if (p >= s->data_end)
+        s->end_transfer_func(s);
+}
+
+static uint32_t ide_data_readw(void *opaque, uint32_t addr)
+{
+    IDEState *s = ((IDEState *)opaque)->cur_drive;
+    uint8_t *p;
+    int ret;
+    p = s->data_ptr;
+    ret = cpu_to_le16(*(uint16_t *)p);
+    p += 2;
+    s->data_ptr = p;
+    if (p >= s->data_end)
+        s->end_transfer_func(s);
+    return ret;
+}
+
+static void ide_data_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+    IDEState *s = ((IDEState *)opaque)->cur_drive;
+    uint8_t *p;
+
+    p = s->data_ptr;
+    *(uint32_t *)p = le32_to_cpu(val);
+    p += 4;
+    s->data_ptr = p;
+    if (p >= s->data_end)
+        s->end_transfer_func(s);
+}
+
+static uint32_t ide_data_readl(void *opaque, uint32_t addr)
+{
+    IDEState *s = ((IDEState *)opaque)->cur_drive;
+    uint8_t *p;
+    int ret;
+
+    p = s->data_ptr;
+    ret = cpu_to_le32(*(uint32_t *)p);
+    p += 4;
+    s->data_ptr = p;
+    if (p >= s->data_end)
+        s->end_transfer_func(s);
+    return ret;
+}
+
+static void ide_dummy_transfer_stop(IDEState *s)
+{
+    s->data_ptr = s->io_buffer;
+    s->data_end = s->io_buffer;
+    s->io_buffer[0] = 0xff;
+    s->io_buffer[1] = 0xff;
+    s->io_buffer[2] = 0xff;
+    s->io_buffer[3] = 0xff;
+}
+
+static void ide_reset(IDEState *s)
+{
+    if (s->is_cf)
+        s->mult_sectors = 0;
+    else
+        s->mult_sectors = MAX_MULT_SECTORS;
+    s->cur_drive = s;
+    s->select = 0xa0;
+    s->status = READY_STAT;
+    ide_set_signature(s);
+    /* init the transfer handler so that 0xffff is returned on data
+       accesses */
+    s->end_transfer_func = ide_dummy_transfer_stop;
+    ide_dummy_transfer_stop(s);
+    s->media_changed = 0;
+}
+
+struct partition {
+       uint8_t boot_ind;               /* 0x80 - active */
+       uint8_t head;           /* starting head */
+       uint8_t sector;         /* starting sector */
+       uint8_t cyl;            /* starting cylinder */
+       uint8_t sys_ind;                /* What partition type */
+       uint8_t end_head;               /* end head */
+       uint8_t end_sector;     /* end sector */
+       uint8_t end_cyl;                /* end cylinder */
+       uint32_t start_sect;    /* starting sector counting from 0 */
+       uint32_t nr_sects;              /* nr of sectors in partition */
+} __attribute__((packed));
+
+/* try to guess the disk logical geometry from the MSDOS partition table. 
Return 0 if OK, -1 if could not guess */
+static int guess_disk_lchs(IDEState *s,
+                           int *pcylinders, int *pheads, int *psectors)
+{
+#ifdef IOEMU
+    uint8_t *buf = s->io_buffer;
+#else
+    uint8_t buf[512];
+#endif
+    int ret, i, heads, sectors, cylinders;
+    struct partition *p;
+    uint32_t nr_sects;
+
+    ret = bdrv_read(s->bs, 0, buf, 1);
+    if (ret < 0)
+        return -1;
+    /* test msdos magic */
+    if (buf[510] != 0x55 || buf[511] != 0xaa)
+        return -1;
+    for(i = 0; i < 4; i++) {
+        p = ((struct partition *)(buf + 0x1be)) + i;
+        nr_sects = le32_to_cpu(p->nr_sects);
+        if (nr_sects && p->end_head) {
+            /* We make the assumption that the partition terminates on
+               a cylinder boundary */
+            heads = p->end_head + 1;
+            sectors = p->end_sector & 63;
+            if (sectors == 0)
+                continue;
+            cylinders = s->nb_sectors / (heads * sectors);
+            if (cylinders < 1 || cylinders > 16383)
+                continue;
+            *pheads = heads;
+            *psectors = sectors;
+            *pcylinders = cylinders;
+#if 0
+            printf("guessed geometry: LCHS=%d %d %d\n",
+                   cylinders, heads, sectors);
+#endif
+            return 0;
+        }
+    }
+    return -1;
+}
+
+static void ide_init2(IDEState *ide_state,
+                      BlockDriverState *hd0, BlockDriverState *hd1,
+                      qemu_irq irq)
+{
+    IDEState *s;
+    static int drive_serial = 1;
+    int i, cylinders, heads, secs, translation, lba_detected = 0;
+    int64_t nb_sectors;
+
+    for(i = 0; i < 2; i++) {
+        s = ide_state + i;
+        if (i == 0)
+            s->bs = hd0;
+        else
+            s->bs = hd1;
+        if (s->bs) {
+            bdrv_get_geometry(s->bs, &nb_sectors);
+            s->nb_sectors = nb_sectors;
+            /* if a geometry hint is available, use it */
+            bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs);
+            translation = bdrv_get_translation_hint(s->bs);
+            if (cylinders != 0) {
+                s->cylinders = cylinders;
+                s->heads = heads;
+                s->sectors = secs;
+            } else {
+                if (guess_disk_lchs(s, &cylinders, &heads, &secs) == 0) {
+                    if (heads > 16) {
+                        /* if heads > 16, it means that a BIOS LBA
+                           translation was active, so the default
+                           hardware geometry is OK */
+                        lba_detected = 1;
+                        goto default_geometry;
+                    } else {
+                        s->cylinders = cylinders;
+                        s->heads = heads;
+                        s->sectors = secs;
+                        /* disable any translation to be in sync with
+                           the logical geometry */
+                        if (translation == BIOS_ATA_TRANSLATION_AUTO) {
+                            bdrv_set_translation_hint(s->bs,
+                                                      
BIOS_ATA_TRANSLATION_NONE);
+                        }
+                    }
+                } else {
+                default_geometry:
+                    /* if no geometry, use a standard physical disk geometry */
+                    cylinders = nb_sectors / (16 * 63);
+                    if (cylinders > 16383)
+                        cylinders = 16383;
+                    else if (cylinders < 2)
+                        cylinders = 2;
+                    s->cylinders = cylinders;
+                    s->heads = 16;
+                    s->sectors = 63;
+                    if ((lba_detected == 1) && (translation == 
BIOS_ATA_TRANSLATION_AUTO)) {
+                      if ((s->cylinders * s->heads) <= 131072) {
+                        bdrv_set_translation_hint(s->bs,
+                                                  BIOS_ATA_TRANSLATION_LARGE);
+                      } else {
+                        bdrv_set_translation_hint(s->bs,
+                                                  BIOS_ATA_TRANSLATION_LBA);
+                      }
+                    }
+                }
+                bdrv_set_geometry_hint(s->bs, s->cylinders, s->heads, 
s->sectors);
+            }
+            if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
+                s->is_cdrom = 1;
+               bdrv_set_change_cb(s->bs, cdrom_change_cb, s);
+            }
+        }
+        s->drive_serial = drive_serial++;
+        s->irq = irq;
+#ifdef TARGET_I386
+        s->sector_write_timer = qemu_new_timer(vm_clock,
+                                               ide_sector_write_timer_cb, s);
+#endif
+        ide_reset(s);
+    }
+}
+
+static void ide_init_ioport(IDEState *ide_state, int iobase, int iobase2)
+{
+    register_ioport_write(iobase, 8, 1, ide_ioport_write, ide_state);
+    register_ioport_read(iobase, 8, 1, ide_ioport_read, ide_state);
+    if (iobase2) {
+        register_ioport_read(iobase2, 1, 1, ide_status_read, ide_state);
+        register_ioport_write(iobase2, 1, 1, ide_cmd_write, ide_state);
+    }
+
+    /* data ports */
+    register_ioport_write(iobase, 2, 2, ide_data_writew, ide_state);
+    register_ioport_read(iobase, 2, 2, ide_data_readw, ide_state);
+    register_ioport_write(iobase, 4, 4, ide_data_writel, ide_state);
+    register_ioport_read(iobase, 4, 4, ide_data_readl, ide_state);
+}
+
+#ifndef IOEMU
+/* save per IDE drive data */
+static void ide_save(QEMUFile* f, IDEState *s)
+{
+    qemu_put_be32s(f, &s->mult_sectors);
+    qemu_put_be32s(f, &s->identify_set);
+    if (s->identify_set) {
+        qemu_put_buffer(f, (const uint8_t *)s->identify_data, 512);
+    }
+    qemu_put_8s(f, &s->feature);
+    qemu_put_8s(f, &s->error);
+    qemu_put_be32s(f, &s->nsector);
+    qemu_put_8s(f, &s->sector);
+    qemu_put_8s(f, &s->lcyl);
+    qemu_put_8s(f, &s->hcyl);
+    qemu_put_8s(f, &s->hob_feature);
+    qemu_put_8s(f, &s->hob_nsector);
+    qemu_put_8s(f, &s->hob_sector);
+    qemu_put_8s(f, &s->hob_lcyl);
+    qemu_put_8s(f, &s->hob_hcyl);
+    qemu_put_8s(f, &s->select);
+    qemu_put_8s(f, &s->status);
+    qemu_put_8s(f, &s->lba48);
+
+    qemu_put_8s(f, &s->sense_key);
+    qemu_put_8s(f, &s->asc);
+    /* XXX: if a transfer is pending, we do not save it yet */
+}
+
+/* load per IDE drive data */
+static void ide_load(QEMUFile* f, IDEState *s)
+{
+    qemu_get_be32s(f, &s->mult_sectors);
+    qemu_get_be32s(f, &s->identify_set);
+    if (s->identify_set) {
+        qemu_get_buffer(f, (uint8_t *)s->identify_data, 512);
+    }
+    qemu_get_8s(f, &s->feature);
+    qemu_get_8s(f, &s->error);
+    qemu_get_be32s(f, &s->nsector);
+    qemu_get_8s(f, &s->sector);
+    qemu_get_8s(f, &s->lcyl);
+    qemu_get_8s(f, &s->hcyl);
+    qemu_get_8s(f, &s->hob_feature);
+    qemu_get_8s(f, &s->hob_nsector);
+    qemu_get_8s(f, &s->hob_sector);
+    qemu_get_8s(f, &s->hob_lcyl);
+    qemu_get_8s(f, &s->hob_hcyl);
+    qemu_get_8s(f, &s->select);
+    qemu_get_8s(f, &s->status);
+    qemu_get_8s(f, &s->lba48);
+
+    qemu_get_8s(f, &s->sense_key);
+    qemu_get_8s(f, &s->asc);
+    /* XXX: if a transfer is pending, we do not save it yet */
+}
+#endif
+
+#ifndef IOEMU
+/***********************************************************/
+/* ISA IDE definitions */
+
+void isa_ide_init(int iobase, int iobase2, qemu_irq irq,
+                  BlockDriverState *hd0, BlockDriverState *hd1)
+{
+    IDEState *ide_state;
+
+    ide_state = qemu_mallocz(sizeof(IDEState) * 2);
+    if (!ide_state)
+        return;
+
+    ide_init2(ide_state, hd0, hd1, irq);
+    ide_init_ioport(ide_state, iobase, iobase2);
+}
+#endif
+
+/***********************************************************/
+/* PCI IDE definitions */
+
+static void cmd646_update_irq(PCIIDEState *d);
+
+static void ide_map(PCIDevice *pci_dev, int region_num,
+                    uint32_t addr, uint32_t size, int type)
+{
+    PCIIDEState *d = (PCIIDEState *)pci_dev;
+    IDEState *ide_state;
+
+    if (region_num <= 3) {
+        ide_state = &d->ide_if[(region_num >> 1) * 2];
+        if (region_num & 1) {
+            register_ioport_read(addr + 2, 1, 1, ide_status_read, ide_state);
+            register_ioport_write(addr + 2, 1, 1, ide_cmd_write, ide_state);
+        } else {
+            register_ioport_write(addr, 8, 1, ide_ioport_write, ide_state);
+            register_ioport_read(addr, 8, 1, ide_ioport_read, ide_state);
+
+            /* data ports */
+            register_ioport_write(addr, 2, 2, ide_data_writew, ide_state);
+            register_ioport_read(addr, 2, 2, ide_data_readw, ide_state);
+            register_ioport_write(addr, 4, 4, ide_data_writel, ide_state);
+            register_ioport_read(addr, 4, 4, ide_data_readl, ide_state);
+        }
+    }
+}
+
+static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb)
+{
+    BMDMAState *bm = s->bmdma;
+    if(!bm)
+        return;
+    bm->ide_if = s;
+    bm->dma_cb = dma_cb;
+    bm->cur_prd_last = 0;
+    bm->cur_prd_addr = 0;
+    bm->cur_prd_len = 0;
+    if (bm->status & BM_STATUS_DMAING) {
+        bm->dma_cb(bm, 0);
+    }
+}
+
+static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    BMDMAState *bm = opaque;
+#ifdef DEBUG_IDE
+    printf("%s: 0x%08x\n", __func__, val);
+#endif
+    if (!(val & BM_CMD_START)) {
+        /* XXX: do it better */
+        if (bm->status & BM_STATUS_DMAING) {
+            bm->status &= ~BM_STATUS_DMAING;
+            /* cancel DMA request */
+            bm->ide_if = NULL;
+            bm->dma_cb = NULL;
+            if (bm->aiocb) {
+#ifdef DEBUG_AIO
+                printf("aio_cancel\n");
+#endif
+                bdrv_aio_cancel(bm->aiocb);
+                bm->aiocb = NULL;
+            }
+        }
+        bm->cmd = val & 0x09;
+    } else {
+        if (!(bm->status & BM_STATUS_DMAING)) {
+            bm->status |= BM_STATUS_DMAING;
+            /* start dma transfer if possible */
+            if (bm->dma_cb)
+                bm->dma_cb(bm, 0);
+        }
+        bm->cmd = val & 0x09;
+    }
+}
+
+static uint32_t bmdma_readb(void *opaque, uint32_t addr)
+{
+    BMDMAState *bm = opaque;
+    PCIIDEState *pci_dev;
+    uint32_t val;
+
+    switch(addr & 3) {
+    case 0:
+        val = bm->cmd;
+        break;
+    case 1:
+        pci_dev = bm->pci_dev;
+        if (pci_dev->type == IDE_TYPE_CMD646) {
+            val = pci_dev->dev.config[MRDMODE];
+        } else {
+            val = 0xff;
+        }
+        break;
+    case 2:
+        val = bm->status;
+        break;
+    case 3:
+        pci_dev = bm->pci_dev;
+        if (pci_dev->type == IDE_TYPE_CMD646) {
+            if (bm == &pci_dev->bmdma[0])
+                val = pci_dev->dev.config[UDIDETCR0];
+            else
+                val = pci_dev->dev.config[UDIDETCR1];
+        } else {
+            val = 0xff;
+        }
+        break;
+    default:
+        val = 0xff;
+        break;
+    }
+#ifdef DEBUG_IDE
+    printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val);
+#endif
+    return val;
+}
+
+static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    BMDMAState *bm = opaque;
+    PCIIDEState *pci_dev;
+#ifdef DEBUG_IDE
+    printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
+#endif
+    switch(addr & 3) {
+    case 1:
+        pci_dev = bm->pci_dev;
+        if (pci_dev->type == IDE_TYPE_CMD646) {
+            pci_dev->dev.config[MRDMODE] =
+                (pci_dev->dev.config[MRDMODE] & ~0x30) | (val & 0x30);
+            cmd646_update_irq(pci_dev);
+        }
+        break;
+    case 2:
+        bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 
0x06);
+        break;
+    case 3:
+        pci_dev = bm->pci_dev;
+        if (pci_dev->type == IDE_TYPE_CMD646) {
+            if (bm == &pci_dev->bmdma[0])
+                pci_dev->dev.config[UDIDETCR0] = val;
+            else
+                pci_dev->dev.config[UDIDETCR1] = val;
+        }
+        break;
+    }
+}
+
+static uint32_t bmdma_addr_readl(void *opaque, uint32_t addr)
+{
+    BMDMAState *bm = opaque;
+    uint32_t val;
+    val = bm->addr;
+#ifdef DEBUG_IDE
+    printf("%s: 0x%08x\n", __func__, val);
+#endif
+    return val;
+}
+
+static void bmdma_addr_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+    BMDMAState *bm = opaque;
+#ifdef DEBUG_IDE
+    printf("%s: 0x%08x\n", __func__, val);
+#endif
+    bm->addr = val & ~3;
+    bm->cur_addr = bm->addr;
+}
+
+static void bmdma_map(PCIDevice *pci_dev, int region_num,
+                    uint32_t addr, uint32_t size, int type)
+{
+    PCIIDEState *d = (PCIIDEState *)pci_dev;
+    int i;
+
+    for(i = 0;i < 2; i++) {
+        BMDMAState *bm = &d->bmdma[i];
+        d->ide_if[2 * i].bmdma = bm;
+        d->ide_if[2 * i + 1].bmdma = bm;
+        bm->pci_dev = (PCIIDEState *)pci_dev;
+
+        register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
+
+        register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
+        register_ioport_read(addr, 4, 1, bmdma_readb, bm);
+
+        register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
+        register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
+        addr += 8;
+    }
+}
+
+/* XXX: call it also when the MRDMODE is changed from the PCI config
+   registers */
+static void cmd646_update_irq(PCIIDEState *d)
+{
+    int pci_level;
+    pci_level = ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH0) &&
+                 !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH0)) ||
+        ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH1) &&
+         !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH1));
+    qemu_set_irq(d->dev.irq[0], pci_level);
+}
+
+/* the PCI irq level is the logical OR of the two channels */
+static void cmd646_set_irq(void *opaque, int channel, int level)
+{
+    PCIIDEState *d = opaque;
+    int irq_mask;
+
+    irq_mask = MRDMODE_INTR_CH0 << channel;
+    if (level)
+        d->dev.config[MRDMODE] |= irq_mask;
+    else
+        d->dev.config[MRDMODE] &= ~irq_mask;
+    cmd646_update_irq(d);
+}
+
+/* CMD646 PCI IDE controller */
+void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table,
+                         int secondary_ide_enabled)
+{
+    PCIIDEState *d;
+    uint8_t *pci_conf;
+    int i;
+    qemu_irq *irq;
+
+    d = (PCIIDEState *)pci_register_device(bus, "CMD646 IDE",
+                                           sizeof(PCIIDEState),
+                                           -1,
+                                           NULL, NULL);
+#ifdef IOEMU
+    for (i = 0; i < 4; i++)
+      d->ide_if[i].io_buffer = alloc_pages
+       (((MAX_MULT_SECTORS * 512 + 4) + PAGE_SIZE - 1) >> PAGE_SHIFT);
+#endif
+    d->type = IDE_TYPE_CMD646;
+    pci_conf = d->dev.config;
+    pci_conf[0x00] = 0x95; // CMD646
+    pci_conf[0x01] = 0x10;
+    pci_conf[0x02] = 0x46;
+    pci_conf[0x03] = 0x06;
+
+    pci_conf[0x08] = 0x07; // IDE controller revision
+    pci_conf[0x09] = 0x8f;
+
+    pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE
+    pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
+    pci_conf[0x0e] = 0x00; // header_type
+
+    if (secondary_ide_enabled) {
+        /* XXX: if not enabled, really disable the seconday IDE controller */
+        pci_conf[0x51] = 0x80; /* enable IDE1 */
+    }
+
+    pci_register_io_region((PCIDevice *)d, 0, 0x8,
+                           PCI_ADDRESS_SPACE_IO, ide_map);
+    pci_register_io_region((PCIDevice *)d, 1, 0x4,
+                           PCI_ADDRESS_SPACE_IO, ide_map);
+    pci_register_io_region((PCIDevice *)d, 2, 0x8,
+                           PCI_ADDRESS_SPACE_IO, ide_map);
+    pci_register_io_region((PCIDevice *)d, 3, 0x4,
+                           PCI_ADDRESS_SPACE_IO, ide_map);
+    pci_register_io_region((PCIDevice *)d, 4, 0x10,
+                           PCI_ADDRESS_SPACE_IO, bmdma_map);
+
+    pci_conf[0x3d] = 0x01; // interrupt on pin 1
+
+    for(i = 0; i < 4; i++)
+        d->ide_if[i].pci_dev = (PCIDevice *)d;
+
+    irq = qemu_allocate_irqs(cmd646_set_irq, d, 2);
+    ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], irq[0]);
+    ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], irq[1]);
+}
+
+#ifndef IOEMU
+static void pci_ide_save(QEMUFile* f, void *opaque)
+{
+    PCIIDEState *d = opaque;
+    int i;
+
+    pci_device_save(&d->dev, f);
+
+    for(i = 0; i < 2; i++) {
+        BMDMAState *bm = &d->bmdma[i];
+        qemu_put_8s(f, &bm->cmd);
+        qemu_put_8s(f, &bm->status);
+        qemu_put_be32s(f, &bm->addr);
+        /* XXX: if a transfer is pending, we do not save it yet */
+    }
+
+    /* per IDE interface data */
+    for(i = 0; i < 2; i++) {
+        IDEState *s = &d->ide_if[i * 2];
+        uint8_t drive1_selected;
+        qemu_put_8s(f, &s->cmd);
+        drive1_selected = (s->cur_drive != s);
+        qemu_put_8s(f, &drive1_selected);
+    }
+
+    /* per IDE drive data */
+    for(i = 0; i < 4; i++) {
+        ide_save(f, &d->ide_if[i]);
+    }
+}
+
+static int pci_ide_load(QEMUFile* f, void *opaque, int version_id)
+{
+    PCIIDEState *d = opaque;
+    int ret, i;
+
+    if (version_id != 1)
+        return -EINVAL;
+    ret = pci_device_load(&d->dev, f);
+    if (ret < 0)
+        return ret;
+
+    for(i = 0; i < 2; i++) {
+        BMDMAState *bm = &d->bmdma[i];
+        qemu_get_8s(f, &bm->cmd);
+        qemu_get_8s(f, &bm->status);
+        qemu_get_be32s(f, &bm->addr);
+        /* XXX: if a transfer is pending, we do not save it yet */
+    }
+
+    /* per IDE interface data */
+    for(i = 0; i < 2; i++) {
+        IDEState *s = &d->ide_if[i * 2];
+        uint8_t drive1_selected;
+        qemu_get_8s(f, &s->cmd);
+        qemu_get_8s(f, &drive1_selected);
+        s->cur_drive = &d->ide_if[i * 2 + (drive1_selected != 0)];
+    }
+
+    /* per IDE drive data */
+    for(i = 0; i < 4; i++) {
+        ide_load(f, &d->ide_if[i]);
+    }
+    return 0;
+}
+#endif
+
+static void piix3_reset(PCIIDEState *d)
+{
+    uint8_t *pci_conf = d->dev.config;
+
+    pci_conf[0x04] = 0x00;
+    pci_conf[0x05] = 0x00;
+    pci_conf[0x06] = 0x80; /* FBC */
+    pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
+    pci_conf[0x20] = 0x01; /* BMIBA: 20-23h */
+}
+
+/* hd_table must contain 4 block drivers */
+/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
+void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
+                        qemu_irq *pic)
+{
+    PCIIDEState *d;
+    uint8_t *pci_conf;
+
+    /* register a function 1 of PIIX3 */
+    d = (PCIIDEState *)pci_register_device(bus, "PIIX3 IDE",
+                                           sizeof(PCIIDEState),
+                                           devfn,
+                                           NULL, NULL);
+    d->type = IDE_TYPE_PIIX3;
+#ifdef IOEMU
+    int i;
+    for (i = 0; i < 4; i++)
+      d->ide_if[i].io_buffer = alloc_pages
+       (((MAX_MULT_SECTORS * 512 + 4) + PAGE_SIZE - 1) >> PAGE_SHIFT);
+#endif
+
+    pci_conf = d->dev.config;
+    pci_conf[0x00] = 0x86; // Intel
+    pci_conf[0x01] = 0x80;
+    pci_conf[0x02] = 0x10;
+    pci_conf[0x03] = 0x70;
+    pci_conf[0x09] = 0x80; // legacy ATA mode
+    pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE
+    pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
+    pci_conf[0x0e] = 0x00; // header_type
+
+    piix3_reset(d);
+
+    pci_register_io_region((PCIDevice *)d, 4, 0x10,
+                           PCI_ADDRESS_SPACE_IO, bmdma_map);
+
+    ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], pic[14]);
+    ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], pic[15]);
+    ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6);
+    ide_init_ioport(&d->ide_if[2], 0x170, 0x376);
+
+    register_savevm("ide", 0, 1, pci_ide_save, pci_ide_load, d);
+}
+
+/* hd_table must contain 4 block drivers */
+/* NOTE: for the PIIX4, the IRQs and IOports are hardcoded */
+void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
+                        qemu_irq *pic)
+{
+    PCIIDEState *d;
+    uint8_t *pci_conf;
+
+    /* register a function 1 of PIIX4 */
+    d = (PCIIDEState *)pci_register_device(bus, "PIIX4 IDE",
+                                           sizeof(PCIIDEState),
+                                           devfn,
+                                           NULL, NULL);
+    d->type = IDE_TYPE_PIIX4;
+#ifdef IOEMU
+    int i;
+    for (i = 0; i < 4; i++)
+      d->ide_if[i].io_buffer = alloc_pages
+       (((MAX_MULT_SECTORS * 512 + 4) + PAGE_SIZE - 1) >> PAGE_SHIFT);
+#endif
+
+    pci_conf = d->dev.config;
+    pci_conf[0x00] = 0x86; // Intel
+    pci_conf[0x01] = 0x80;
+    pci_conf[0x02] = 0x11;
+    pci_conf[0x03] = 0x71;
+    pci_conf[0x09] = 0x80; // legacy ATA mode
+    pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE
+    pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
+    pci_conf[0x0e] = 0x00; // header_type
+
+    piix3_reset(d);
+
+    pci_register_io_region((PCIDevice *)d, 4, 0x10,
+                           PCI_ADDRESS_SPACE_IO, bmdma_map);
+
+    ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], pic[14]);
+    ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], pic[15]);
+    ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6);
+    ide_init_ioport(&d->ide_if[2], 0x170, 0x376);
+
+    register_savevm("ide", 0, 1, pci_ide_save, pci_ide_load, d);
+}
+
+#ifndef IOEMU
+/***********************************************************/
+/* MacIO based PowerPC IDE */
+
+/* PowerMac IDE memory IO */
+static void pmac_ide_writeb (void *opaque,
+                             target_phys_addr_t addr, uint32_t val)
+{
+    addr = (addr & 0xFFF) >> 4;
+    switch (addr) {
+    case 1 ... 7:
+        ide_ioport_write(opaque, addr, val);
+        break;
+    case 8:
+    case 22:
+        ide_cmd_write(opaque, 0, val);
+        break;
+    default:
+        break;
+    }
+}
+
+static uint32_t pmac_ide_readb (void *opaque,target_phys_addr_t addr)
+{
+    uint8_t retval;
+
+    addr = (addr & 0xFFF) >> 4;
+    switch (addr) {
+    case 1 ... 7:
+        retval = ide_ioport_read(opaque, addr);
+        break;
+    case 8:
+    case 22:
+        retval = ide_status_read(opaque, 0);
+        break;
+    default:
+        retval = 0xFF;
+        break;
+    }
+    return retval;
+}
+
+static void pmac_ide_writew (void *opaque,
+                             target_phys_addr_t addr, uint32_t val)
+{
+    addr = (addr & 0xFFF) >> 4;
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = bswap16(val);
+#endif
+    if (addr == 0) {
+        ide_data_writew(opaque, 0, val);
+    }
+}
+
+static uint32_t pmac_ide_readw (void *opaque,target_phys_addr_t addr)
+{
+    uint16_t retval;
+
+    addr = (addr & 0xFFF) >> 4;
+    if (addr == 0) {
+        retval = ide_data_readw(opaque, 0);
+    } else {
+        retval = 0xFFFF;
+    }
+#ifdef TARGET_WORDS_BIGENDIAN
+    retval = bswap16(retval);
+#endif
+    return retval;
+}
+
+static void pmac_ide_writel (void *opaque,
+                             target_phys_addr_t addr, uint32_t val)
+{
+    addr = (addr & 0xFFF) >> 4;
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = bswap32(val);
+#endif
+    if (addr == 0) {
+        ide_data_writel(opaque, 0, val);
+    }
+}
+
+static uint32_t pmac_ide_readl (void *opaque,target_phys_addr_t addr)
+{
+    uint32_t retval;
+
+    addr = (addr & 0xFFF) >> 4;
+    if (addr == 0) {
+        retval = ide_data_readl(opaque, 0);
+    } else {
+        retval = 0xFFFFFFFF;
+    }
+#ifdef TARGET_WORDS_BIGENDIAN
+    retval = bswap32(retval);
+#endif
+    return retval;
+}
+
+static CPUWriteMemoryFunc *pmac_ide_write[] = {
+    pmac_ide_writeb,
+    pmac_ide_writew,
+    pmac_ide_writel,
+};
+
+static CPUReadMemoryFunc *pmac_ide_read[] = {
+    pmac_ide_readb,
+    pmac_ide_readw,
+    pmac_ide_readl,
+};
+
+/* hd_table must contain 4 block drivers */
+/* PowerMac uses memory mapped registers, not I/O. Return the memory
+   I/O index to access the ide. */
+int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq)
+{
+    IDEState *ide_if;
+    int pmac_ide_memory;
+
+    ide_if = qemu_mallocz(sizeof(IDEState) * 2);
+    ide_init2(&ide_if[0], hd_table[0], hd_table[1], irq);
+
+    pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read,
+                                             pmac_ide_write, &ide_if[0]);
+    return pmac_ide_memory;
+}
+
+/***********************************************************/
+/* CF-ATA Microdrive */
+
+#define METADATA_SIZE  0x20
+
+/* DSCM-1XXXX Microdrive hard disk with CF+ II / PCMCIA interface.  */
+struct md_s {
+    IDEState ide[2];
+    struct pcmcia_card_s card;
+    uint32_t attr_base;
+    uint32_t io_base;
+
+    /* Card state */
+    uint8_t opt;
+    uint8_t stat;
+    uint8_t pins;
+
+    uint8_t ctrl;
+    uint16_t io;
+    int cycle;
+};
+
+/* Register bitfields */
+enum md_opt {
+    OPT_MODE_MMAP      = 0,
+    OPT_MODE_IOMAP16   = 1,
+    OPT_MODE_IOMAP1    = 2,
+    OPT_MODE_IOMAP2    = 3,
+    OPT_MODE           = 0x3f,
+    OPT_LEVIREQ                = 0x40,
+    OPT_SRESET         = 0x80,
+};
+enum md_cstat {
+    STAT_INT           = 0x02,
+    STAT_PWRDWN                = 0x04,
+    STAT_XE            = 0x10,
+    STAT_IOIS8         = 0x20,
+    STAT_SIGCHG                = 0x40,
+    STAT_CHANGED       = 0x80,
+};
+enum md_pins {
+    PINS_MRDY          = 0x02,
+    PINS_CRDY          = 0x20,
+};
+enum md_ctrl {
+    CTRL_IEN           = 0x02,
+    CTRL_SRST          = 0x04,
+};
+
+static inline void md_interrupt_update(struct md_s *s)
+{
+    if (!s->card.slot)
+        return;
+
+    qemu_set_irq(s->card.slot->irq,
+                    !(s->stat & STAT_INT) &&   /* Inverted */
+                    !(s->ctrl & (CTRL_IEN | CTRL_SRST)) &&
+                    !(s->opt & OPT_SRESET));
+}
+
+static void md_set_irq(void *opaque, int irq, int level)
+{
+    struct md_s *s = (struct md_s *) opaque;
+    if (level)
+        s->stat |= STAT_INT;
+    else
+        s->stat &= ~STAT_INT;
+
+    md_interrupt_update(s);
+}
+
+static void md_reset(struct md_s *s)
+{
+    s->opt = OPT_MODE_MMAP;
+    s->stat = 0;
+    s->pins = 0;
+    s->cycle = 0;
+    s->ctrl = 0;
+    ide_reset(s->ide);
+}
+
+static uint8_t md_attr_read(void *opaque, uint32_t at)
+{
+    struct md_s *s = (struct md_s *) opaque;
+    if (at < s->attr_base) {
+        if (at < s->card.cis_len)
+            return s->card.cis[at];
+        else
+            return 0x00;
+    }
+
+    at -= s->attr_base;
+
+    switch (at) {
+    case 0x00: /* Configuration Option Register */
+        return s->opt;
+    case 0x02: /* Card Configuration Status Register */
+        if (s->ctrl & CTRL_IEN)
+            return s->stat & ~STAT_INT;
+        else
+            return s->stat;
+    case 0x04: /* Pin Replacement Register */
+        return (s->pins & PINS_CRDY) | 0x0c;
+    case 0x06: /* Socket and Copy Register */
+        return 0x00;
+#ifdef VERBOSE
+    default:
+        printf("%s: Bad attribute space register %02x\n", __FUNCTION__, at);
+#endif
+    }
+
+    return 0;
+}
+
+static void md_attr_write(void *opaque, uint32_t at, uint8_t value)
+{
+    struct md_s *s = (struct md_s *) opaque;
+    at -= s->attr_base;
+
+    switch (at) {
+    case 0x00: /* Configuration Option Register */
+        s->opt = value & 0xcf;
+        if (value & OPT_SRESET)
+            md_reset(s);
+        md_interrupt_update(s);
+        break;
+    case 0x02: /* Card Configuration Status Register */
+        if ((s->stat ^ value) & STAT_PWRDWN)
+            s->pins |= PINS_CRDY;
+        s->stat &= 0x82;
+        s->stat |= value & 0x74;
+        md_interrupt_update(s);
+        /* Word 170 in Identify Device must be equal to STAT_XE */
+        break;
+    case 0x04: /* Pin Replacement Register */
+        s->pins &= PINS_CRDY;
+        s->pins |= value & PINS_MRDY;
+        break;
+    case 0x06: /* Socket and Copy Register */
+        break;
+    default:
+        printf("%s: Bad attribute space register %02x\n", __FUNCTION__, at);
+    }
+}
+
+static uint16_t md_common_read(void *opaque, uint32_t at)
+{
+    struct md_s *s = (struct md_s *) opaque;
+    uint16_t ret;
+    at -= s->io_base;
+
+    switch (s->opt & OPT_MODE) {
+    case OPT_MODE_MMAP:
+        if ((at & ~0x3ff) == 0x400)
+            at = 0;
+        break;
+    case OPT_MODE_IOMAP16:
+        at &= 0xf;
+        break;
+    case OPT_MODE_IOMAP1:
+        if ((at & ~0xf) == 0x3f0)
+            at -= 0x3e8;
+        else if ((at & ~0xf) == 0x1f0)
+            at -= 0x1f0;
+        break;
+    case OPT_MODE_IOMAP2:
+        if ((at & ~0xf) == 0x370)
+            at -= 0x368;
+        else if ((at & ~0xf) == 0x170)
+            at -= 0x170;
+    }
+
+    switch (at) {
+    case 0x0:  /* Even RD Data */
+    case 0x8:
+        return ide_data_readw(s->ide, 0);
+
+        /* TODO: 8-bit accesses */
+        if (s->cycle)
+            ret = s->io >> 8;
+        else {
+            s->io = ide_data_readw(s->ide, 0);
+            ret = s->io & 0xff;
+        }
+        s->cycle = !s->cycle;
+        return ret;
+    case 0x9:  /* Odd RD Data */
+        return s->io >> 8;
+    case 0xd:  /* Error */
+        return ide_ioport_read(s->ide, 0x1);
+    case 0xe:  /* Alternate Status */
+        if (s->ide->cur_drive->bs)
+            return s->ide->cur_drive->status;
+        else
+            return 0;
+    case 0xf:  /* Device Address */
+        return 0xc2 | ((~s->ide->select << 2) & 0x3c);
+    default:
+        return ide_ioport_read(s->ide, at);
+    }
+
+    return 0;
+}
+
+static void md_common_write(void *opaque, uint32_t at, uint16_t value)
+{
+    struct md_s *s = (struct md_s *) opaque;
+    at -= s->io_base;
+
+    switch (s->opt & OPT_MODE) {
+    case OPT_MODE_MMAP:
+        if ((at & ~0x3ff) == 0x400)
+            at = 0;
+        break;
+    case OPT_MODE_IOMAP16:
+        at &= 0xf;
+        break;
+    case OPT_MODE_IOMAP1:
+        if ((at & ~0xf) == 0x3f0)
+            at -= 0x3e8;
+        else if ((at & ~0xf) == 0x1f0)
+            at -= 0x1f0;
+        break;
+    case OPT_MODE_IOMAP2:
+        if ((at & ~0xf) == 0x370)
+            at -= 0x368;
+        else if ((at & ~0xf) == 0x170)
+            at -= 0x170;
+    }
+
+    switch (at) {
+    case 0x0:  /* Even WR Data */
+    case 0x8:
+        ide_data_writew(s->ide, 0, value);
+        break;
+
+        /* TODO: 8-bit accesses */
+        if (s->cycle)
+            ide_data_writew(s->ide, 0, s->io | (value << 8));
+        else
+            s->io = value & 0xff;
+        s->cycle = !s->cycle;
+        break;
+    case 0x9:
+        s->io = value & 0xff;
+        s->cycle = !s->cycle;
+        break;
+    case 0xd:  /* Features */
+        ide_ioport_write(s->ide, 0x1, value);
+        break;
+    case 0xe:  /* Device Control */
+        s->ctrl = value;
+        if (value & CTRL_SRST)
+            md_reset(s);
+        md_interrupt_update(s);
+        break;
+    default:
+        if (s->stat & STAT_PWRDWN) {
+            s->pins |= PINS_CRDY;
+            s->stat &= ~STAT_PWRDWN;
+        }
+        ide_ioport_write(s->ide, at, value);
+    }
+}
+
+static void md_save(QEMUFile *f, void *opaque)
+{
+    struct md_s *s = (struct md_s *) opaque;
+    int i;
+    uint8_t drive1_selected;
+
+    qemu_put_8s(f, &s->opt);
+    qemu_put_8s(f, &s->stat);
+    qemu_put_8s(f, &s->pins);
+
+    qemu_put_8s(f, &s->ctrl);
+    qemu_put_be16s(f, &s->io);
+    qemu_put_byte(f, s->cycle);
+
+    drive1_selected = (s->ide->cur_drive != s->ide);
+    qemu_put_8s(f, &s->ide->cmd);
+    qemu_put_8s(f, &drive1_selected);
+
+    for (i = 0; i < 2; i ++)
+        ide_save(f, &s->ide[i]);
+}
+
+static int md_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct md_s *s = (struct md_s *) opaque;
+    int i;
+    uint8_t drive1_selected;
+
+    qemu_get_8s(f, &s->opt);
+    qemu_get_8s(f, &s->stat);
+    qemu_get_8s(f, &s->pins);
+
+    qemu_get_8s(f, &s->ctrl);
+    qemu_get_be16s(f, &s->io);
+    s->cycle = qemu_get_byte(f);
+
+    qemu_get_8s(f, &s->ide->cmd);
+    qemu_get_8s(f, &drive1_selected);
+    s->ide->cur_drive = &s->ide[(drive1_selected != 0)];
+
+    for (i = 0; i < 2; i ++)
+        ide_load(f, &s->ide[i]);
+
+    return 0;
+}
+
+static int md_iid = 0;
+
+static const uint8_t dscm1xxxx_cis[0x14a] = {
+    [0x000] = CISTPL_DEVICE,   /* 5V Device Information */
+    [0x002] = 0x03,            /* Tuple length = 4 bytes */
+    [0x004] = 0xdb,            /* ID: DTYPE_FUNCSPEC, non WP, DSPEED_150NS */
+    [0x006] = 0x01,            /* Size = 2K bytes */
+    [0x008] = CISTPL_ENDMARK,
+
+    [0x00a] = CISTPL_DEVICE_OC,        /* Additional Device Information */
+    [0x00c] = 0x04,            /* Tuple length = 4 byest */
+    [0x00e] = 0x03,            /* Conditions: Ext = 0, Vcc 3.3V, MWAIT = 1 */
+    [0x010] = 0xdb,            /* ID: DTYPE_FUNCSPEC, non WP, DSPEED_150NS */
+    [0x012] = 0x01,            /* Size = 2K bytes */
+    [0x014] = CISTPL_ENDMARK,
+
+    [0x016] = CISTPL_JEDEC_C,  /* JEDEC ID */
+    [0x018] = 0x02,            /* Tuple length = 2 bytes */
+    [0x01a] = 0xdf,            /* PC Card ATA with no Vpp required */
+    [0x01c] = 0x01,
+
+    [0x01e] = CISTPL_MANFID,   /* Manufacture ID */
+    [0x020] = 0x04,            /* Tuple length = 4 bytes */
+    [0x022] = 0xa4,            /* TPLMID_MANF = 00a4 (IBM) */
+    [0x024] = 0x00,
+    [0x026] = 0x00,            /* PLMID_CARD = 0000 */
+    [0x028] = 0x00,
+
+    [0x02a] = CISTPL_VERS_1,   /* Level 1 Version */
+    [0x02c] = 0x12,            /* Tuple length = 23 bytes */
+    [0x02e] = 0x04,            /* Major Version = JEIDA 4.2 / PCMCIA 2.1 */
+    [0x030] = 0x01,            /* Minor Version = 1 */
+    [0x032] = 'I',
+    [0x034] = 'B',
+    [0x036] = 'M',
+    [0x038] = 0x00,
+    [0x03a] = 'm',
+    [0x03c] = 'i',
+    [0x03e] = 'c',
+    [0x040] = 'r',
+    [0x042] = 'o',
+    [0x044] = 'd',
+    [0x046] = 'r',
+    [0x048] = 'i',
+    [0x04a] = 'v',
+    [0x04c] = 'e',
+    [0x04e] = 0x00,
+    [0x050] = CISTPL_ENDMARK,
+
+    [0x052] = CISTPL_FUNCID,   /* Function ID */
+    [0x054] = 0x02,            /* Tuple length = 2 bytes */
+    [0x056] = 0x04,            /* TPLFID_FUNCTION = Fixed Disk */
+    [0x058] = 0x01,            /* TPLFID_SYSINIT: POST = 1, ROM = 0 */
+
+    [0x05a] = CISTPL_FUNCE,    /* Function Extension */
+    [0x05c] = 0x02,            /* Tuple length = 2 bytes */
+    [0x05e] = 0x01,            /* TPLFE_TYPE = Disk Device Interface */
+    [0x060] = 0x01,            /* TPLFE_DATA = PC Card ATA Interface */
+
+    [0x062] = CISTPL_FUNCE,    /* Function Extension */
+    [0x064] = 0x03,            /* Tuple length = 3 bytes */
+    [0x066] = 0x02,            /* TPLFE_TYPE = Basic PC Card ATA Interface */
+    [0x068] = 0x08,            /* TPLFE_DATA: Rotating, Unique, Single */
+    [0x06a] = 0x0f,            /* TPLFE_DATA: Sleep, Standby, Idle, Auto */
+
+    [0x06c] = CISTPL_CONFIG,   /* Configuration */
+    [0x06e] = 0x05,            /* Tuple length = 5 bytes */
+    [0x070] = 0x01,            /* TPCC_RASZ = 2 bytes, TPCC_RMSZ = 1 byte */
+    [0x072] = 0x07,            /* TPCC_LAST = 7 */
+    [0x074] = 0x00,            /* TPCC_RADR = 0200 */
+    [0x076] = 0x02,
+    [0x078] = 0x0f,            /* TPCC_RMSK = 200, 202, 204, 206 */
+
+    [0x07a] = CISTPL_CFTABLE_ENTRY,    /* 16-bit PC Card Configuration */
+    [0x07c] = 0x0b,            /* Tuple length = 11 bytes */
+    [0x07e] = 0xc0,            /* TPCE_INDX = Memory Mode, Default, Iface */
+    [0x080] = 0xc0,            /* TPCE_IF = Memory, no BVDs, no WP, READY */
+    [0x082] = 0xa1,            /* TPCE_FS = Vcc only, no I/O, Memory, Misc */
+    [0x084] = 0x27,            /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
+    [0x086] = 0x55,            /* NomV: 5.0 V */
+    [0x088] = 0x4d,            /* MinV: 4.5 V */
+    [0x08a] = 0x5d,            /* MaxV: 5.5 V */
+    [0x08c] = 0x4e,            /* Peakl: 450 mA */
+    [0x08e] = 0x08,            /* TPCE_MS = 1 window, 1 byte, Host address */
+    [0x090] = 0x00,            /* Window descriptor: Window length = 0 */
+    [0x092] = 0x20,            /* TPCE_MI: support power down mode, RW */
+
+    [0x094] = CISTPL_CFTABLE_ENTRY,    /* 16-bit PC Card Configuration */
+    [0x096] = 0x06,            /* Tuple length = 6 bytes */
+    [0x098] = 0x00,            /* TPCE_INDX = Memory Mode, no Default */
+    [0x09a] = 0x01,            /* TPCE_FS = Vcc only, no I/O, no Memory */
+    [0x09c] = 0x21,            /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
+    [0x09e] = 0xb5,            /* NomV: 3.3 V */
+    [0x0a0] = 0x1e,
+    [0x0a2] = 0x3e,            /* Peakl: 350 mA */
+
+    [0x0a4] = CISTPL_CFTABLE_ENTRY,    /* 16-bit PC Card Configuration */
+    [0x0a6] = 0x0d,            /* Tuple length = 13 bytes */
+    [0x0a8] = 0xc1,            /* TPCE_INDX = I/O and Memory Mode, Default */
+    [0x0aa] = 0x41,            /* TPCE_IF = I/O and Memory, no BVD, no WP */
+    [0x0ac] = 0x99,            /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
+    [0x0ae] = 0x27,            /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
+    [0x0b0] = 0x55,            /* NomV: 5.0 V */
+    [0x0b2] = 0x4d,            /* MinV: 4.5 V */
+    [0x0b4] = 0x5d,            /* MaxV: 5.5 V */
+    [0x0b6] = 0x4e,            /* Peakl: 450 mA */
+    [0x0b8] = 0x64,            /* TPCE_IO = 16-byte boundary, 16/8 accesses */
+    [0x0ba] = 0xf0,            /* TPCE_IR =  MASK, Level, Pulse, Share */
+    [0x0bc] = 0xff,            /* IRQ0..IRQ7 supported */
+    [0x0be] = 0xff,            /* IRQ8..IRQ15 supported */
+    [0x0c0] = 0x20,            /* TPCE_MI = support power down mode */
+
+    [0x0c2] = CISTPL_CFTABLE_ENTRY,    /* 16-bit PC Card Configuration */
+    [0x0c4] = 0x06,            /* Tuple length = 6 bytes */
+    [0x0c6] = 0x01,            /* TPCE_INDX = I/O and Memory Mode */
+    [0x0c8] = 0x01,            /* TPCE_FS = Vcc only, no I/O, no Memory */
+    [0x0ca] = 0x21,            /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
+    [0x0cc] = 0xb5,            /* NomV: 3.3 V */
+    [0x0ce] = 0x1e,
+    [0x0d0] = 0x3e,            /* Peakl: 350 mA */
+
+    [0x0d2] = CISTPL_CFTABLE_ENTRY,    /* 16-bit PC Card Configuration */
+    [0x0d4] = 0x12,            /* Tuple length = 18 bytes */
+    [0x0d6] = 0xc2,            /* TPCE_INDX = I/O Primary Mode */
+    [0x0d8] = 0x41,            /* TPCE_IF = I/O and Memory, no BVD, no WP */
+    [0x0da] = 0x99,            /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
+    [0x0dc] = 0x27,            /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
+    [0x0de] = 0x55,            /* NomV: 5.0 V */
+    [0x0e0] = 0x4d,            /* MinV: 4.5 V */
+    [0x0e2] = 0x5d,            /* MaxV: 5.5 V */
+    [0x0e4] = 0x4e,            /* Peakl: 450 mA */
+    [0x0e6] = 0xea,            /* TPCE_IO = 1K boundary, 16/8 access, Range */
+    [0x0e8] = 0x61,            /* Range: 2 fields, 2 bytes addr, 1 byte len */
+    [0x0ea] = 0xf0,            /* Field 1 address = 0x01f0 */
+    [0x0ec] = 0x01,
+    [0x0ee] = 0x07,            /* Address block length = 8 */
+    [0x0f0] = 0xf6,            /* Field 2 address = 0x03f6 */
+    [0x0f2] = 0x03,
+    [0x0f4] = 0x01,            /* Address block length = 2 */
+    [0x0f6] = 0xee,            /* TPCE_IR = IRQ E, Level, Pulse, Share */
+    [0x0f8] = 0x20,            /* TPCE_MI = support power down mode */
+
+    [0x0fa] = CISTPL_CFTABLE_ENTRY,    /* 16-bit PC Card Configuration */
+    [0x0fc] = 0x06,            /* Tuple length = 6 bytes */
+    [0x0fe] = 0x02,            /* TPCE_INDX = I/O Primary Mode, no Default */
+    [0x100] = 0x01,            /* TPCE_FS = Vcc only, no I/O, no Memory */
+    [0x102] = 0x21,            /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
+    [0x104] = 0xb5,            /* NomV: 3.3 V */
+    [0x106] = 0x1e,
+    [0x108] = 0x3e,            /* Peakl: 350 mA */
+
+    [0x10a] = CISTPL_CFTABLE_ENTRY,    /* 16-bit PC Card Configuration */
+    [0x10c] = 0x12,            /* Tuple length = 18 bytes */
+    [0x10e] = 0xc3,            /* TPCE_INDX = I/O Secondary Mode, Default */
+    [0x110] = 0x41,            /* TPCE_IF = I/O and Memory, no BVD, no WP */
+    [0x112] = 0x99,            /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
+    [0x114] = 0x27,            /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
+    [0x116] = 0x55,            /* NomV: 5.0 V */
+    [0x118] = 0x4d,            /* MinV: 4.5 V */
+    [0x11a] = 0x5d,            /* MaxV: 5.5 V */
+    [0x11c] = 0x4e,            /* Peakl: 450 mA */
+    [0x11e] = 0xea,            /* TPCE_IO = 1K boundary, 16/8 access, Range */
+    [0x120] = 0x61,            /* Range: 2 fields, 2 byte addr, 1 byte len */
+    [0x122] = 0x70,            /* Field 1 address = 0x0170 */
+    [0x124] = 0x01,
+    [0x126] = 0x07,            /* Address block length = 8 */
+    [0x128] = 0x76,            /* Field 2 address = 0x0376 */
+    [0x12a] = 0x03,
+    [0x12c] = 0x01,            /* Address block length = 2 */
+    [0x12e] = 0xee,            /* TPCE_IR = IRQ E, Level, Pulse, Share */
+    [0x130] = 0x20,            /* TPCE_MI = support power down mode */
+
+    [0x132] = CISTPL_CFTABLE_ENTRY,    /* 16-bit PC Card Configuration */
+    [0x134] = 0x06,            /* Tuple length = 6 bytes */
+    [0x136] = 0x03,            /* TPCE_INDX = I/O Secondary Mode */
+    [0x138] = 0x01,            /* TPCE_FS = Vcc only, no I/O, no Memory */
+    [0x13a] = 0x21,            /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
+    [0x13c] = 0xb5,            /* NomV: 3.3 V */
+    [0x13e] = 0x1e,
+    [0x140] = 0x3e,            /* Peakl: 350 mA */
+
+    [0x142] = CISTPL_NO_LINK,  /* No Link */
+    [0x144] = 0x00,            /* Tuple length = 0 bytes */
+
+    [0x146] = CISTPL_END,      /* Tuple End */
+};
+
+static int dscm1xxxx_attach(void *opaque)
+{
+    struct md_s *md = (struct md_s *) opaque;
+    md->card.attr_read = md_attr_read;
+    md->card.attr_write = md_attr_write;
+    md->card.common_read = md_common_read;
+    md->card.common_write = md_common_write;
+    md->card.io_read = md_common_read;
+    md->card.io_write = md_common_write;
+
+    md->attr_base = md->card.cis[0x74] | (md->card.cis[0x76] << 8);
+    md->io_base = 0x0;
+
+    md_reset(md);
+    md_interrupt_update(md);
+
+    md->card.slot->card_string = "DSCM-1xxxx Hitachi Microdrive";
+    return 0;
+}
+
+static int dscm1xxxx_detach(void *opaque)
+{
+    struct md_s *md = (struct md_s *) opaque;
+    md_reset(md);
+    return 0;
+}
+
+struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv)
+{
+    struct md_s *md = (struct md_s *) qemu_mallocz(sizeof(struct md_s));
+    md->card.state = md;
+    md->card.attach = dscm1xxxx_attach;
+    md->card.detach = dscm1xxxx_detach;
+    md->card.cis = dscm1xxxx_cis;
+    md->card.cis_len = sizeof(dscm1xxxx_cis);
+
+    ide_init2(md->ide, bdrv, 0, qemu_allocate_irqs(md_set_irq, md, 1)[0]);
+    md->ide->is_cf = 1;
+    md->ide->mdata_size = METADATA_SIZE;
+    md->ide->mdata_storage = (uint8_t *) qemu_mallocz(METADATA_SIZE);
+
+    register_savevm("microdrive", md_iid ++, 0, md_save, md_load, md);
+
+    return &md->card;
+}
+#endif
+
diff -r 092232fa1fbd extras/stubfw/ioemu/irq.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/ioemu/irq.c Fri Nov 16 03:43:56 2007 +0100
@@ -0,0 +1,72 @@
+/*
+ * QEMU IRQ/GPIO common code.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+struct IRQState {
+    qemu_irq_handler handler;
+    void *opaque;
+    int n;
+};
+
+void qemu_set_irq(qemu_irq irq, int level)
+{
+    if (!irq)
+        return;
+
+    if (irq->n == 0)
+      printk ("qemu_set_irq: irq=%d, caller=%lx\n", irq->n,
+             __builtin_return_address (0));
+    //printf("qemu_set_irq: irq=%d lvl=%d (not implemented)\n", irq->n, level);
+    irq->handler(irq->opaque, irq->n, level);
+}
+
+qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n)
+{
+    qemu_irq *s;
+    struct IRQState *p;
+    int i;
+
+    s = (qemu_irq *)qemu_mallocz(sizeof(qemu_irq) * n);
+    p = (struct IRQState *)qemu_mallocz(sizeof(struct IRQState) * n);
+    for (i = 0; i < n; i++) {
+        p->handler = handler;
+        p->opaque = opaque;
+        p->n = i;
+        s[i] = p;
+        p++;
+    }
+    return s;
+}
+
+static void qemu_notirq(void *opaque, int line, int level)
+{
+    struct IRQState *irq = opaque;
+
+    irq->handler(irq->opaque, irq->n, !level);
+}
+
+qemu_irq qemu_irq_invert(qemu_irq irq)
+{
+    return qemu_allocate_irqs(qemu_notirq, irq, 1)[0];
+}
diff -r 092232fa1fbd extras/stubfw/ioemu/mc146818rtc.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/ioemu/mc146818rtc.c Wed Nov 21 16:13:21 2007 +0100
@@ -0,0 +1,625 @@
+/*
+ * QEMU MC146818 RTC emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+//#define DEBUG_CMOS
+
+#define RTC_SECONDS             0
+#define RTC_SECONDS_ALARM       1
+#define RTC_MINUTES             2
+#define RTC_MINUTES_ALARM       3
+#define RTC_HOURS               4
+#define RTC_HOURS_ALARM         5
+#define RTC_ALARM_DONT_CARE    0xC0
+
+#define RTC_DAY_OF_WEEK         6
+#define RTC_DAY_OF_MONTH        7
+#define RTC_MONTH               8
+#define RTC_YEAR                9
+
+#define RTC_REG_A               10
+#define RTC_REG_B               11
+#define RTC_REG_C               12
+#define RTC_REG_D               13
+
+#define REG_A_UIP 0x80
+
+#define REG_B_SET 0x80
+#define REG_B_PIE 0x40
+#define REG_B_AIE 0x20
+#define REG_B_UIE 0x10
+
+struct RTCState {
+    uint8_t cmos_data[128];
+    uint8_t cmos_index;
+  //    struct tm current_tm;
+    qemu_irq irq;
+    target_phys_addr_t base;
+    int it_shift;
+#ifndef IOEMU
+    /* periodic timer */
+    QEMUTimer *periodic_timer;
+    int64_t next_periodic_time;
+    /* second update */
+    int64_t next_second_time;
+    QEMUTimer *second_timer;
+    QEMUTimer *second_timer2;
+#endif
+};
+
+#ifndef IOEMU
+static void rtc_set_time(RTCState *s);
+static void rtc_copy_date(RTCState *s);
+
+static void rtc_timer_update(RTCState *s, int64_t current_time)
+{
+    int period_code, period;
+    int64_t cur_clock, next_irq_clock;
+
+    period_code = s->cmos_data[RTC_REG_A] & 0x0f;
+    if (period_code != 0 &&
+        (s->cmos_data[RTC_REG_B] & REG_B_PIE)) {
+        if (period_code <= 2)
+            period_code += 7;
+        /* period in 32 Khz cycles */
+        period = 1 << (period_code - 1);
+        /* compute 32 khz clock */
+        cur_clock = muldiv64(current_time, 32768, ticks_per_sec);
+        next_irq_clock = (cur_clock & ~(period - 1)) + period;
+        s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) 
+ 1;
+        qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
+    } else {
+        qemu_del_timer(s->periodic_timer);
+    }
+}
+
+static void rtc_periodic_timer(void *opaque)
+{
+    RTCState *s = opaque;
+
+    rtc_timer_update(s, s->next_periodic_time);
+    s->cmos_data[RTC_REG_C] |= 0xc0;
+    qemu_irq_raise(s->irq);
+}
+#endif
+
+void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
+{
+    RTCState *s = opaque;
+
+    if ((addr & 1) == 0) {
+        s->cmos_index = data & 0x7f;
+    } else {
+#ifdef DEBUG_CMOS
+        printf("cmos: write index=0x%02x val=0x%02x\n",
+               s->cmos_index, data);
+#endif
+        switch(s->cmos_index) {
+        case RTC_SECONDS_ALARM:
+        case RTC_MINUTES_ALARM:
+        case RTC_HOURS_ALARM:
+            /* XXX: not supported */
+            s->cmos_data[s->cmos_index] = data;
+            break;
+        case RTC_SECONDS:
+        case RTC_MINUTES:
+        case RTC_HOURS:
+        case RTC_DAY_OF_WEEK:
+        case RTC_DAY_OF_MONTH:
+        case RTC_MONTH:
+        case RTC_YEAR:
+            s->cmos_data[s->cmos_index] = data;
+            /* if in set mode, do not update the time */
+            if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
+#ifndef IOEMU
+                rtc_set_time(s);
+#endif
+            }
+            break;
+        case RTC_REG_A:
+            /* UIP bit is read only */
+            s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
+                (s->cmos_data[RTC_REG_A] & REG_A_UIP);
+#ifndef IOEMU
+            rtc_timer_update(s, qemu_get_clock(vm_clock));
+#endif
+            break;
+        case RTC_REG_B:
+            if (data & REG_B_SET) {
+                /* set mode: reset UIP mode */
+                s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
+                data &= ~REG_B_UIE;
+            } else {
+                /* if disabling set mode, update the time */
+                if (s->cmos_data[RTC_REG_B] & REG_B_SET) {
+#ifndef IOEMU
+                    rtc_set_time(s);
+#endif
+                }
+            }
+            s->cmos_data[RTC_REG_B] = data;
+#ifndef IOEMU
+            rtc_timer_update(s, qemu_get_clock(vm_clock));
+#endif
+            break;
+        case RTC_REG_C:
+        case RTC_REG_D:
+            /* cannot write to them */
+            break;
+        default:
+            s->cmos_data[s->cmos_index] = data;
+            break;
+        }
+    }
+}
+
+static inline int to_bcd(RTCState *s, int a)
+{
+    if (s->cmos_data[RTC_REG_B] & 0x04) {
+        return a;
+    } else {
+        return ((a / 10) << 4) | (a % 10);
+    }
+}
+
+static inline int from_bcd(RTCState *s, int a)
+{
+    if (s->cmos_data[RTC_REG_B] & 0x04) {
+        return a;
+    } else {
+        return ((a >> 4) * 10) + (a & 0x0f);
+    }
+}
+
+#ifndef IOEMU
+static void rtc_set_time(RTCState *s)
+{
+    struct tm *tm = &s->current_tm;
+
+    tm->tm_sec = from_bcd(s, s->cmos_data[RTC_SECONDS]);
+    tm->tm_min = from_bcd(s, s->cmos_data[RTC_MINUTES]);
+    tm->tm_hour = from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
+    if (!(s->cmos_data[RTC_REG_B] & 0x02) &&
+        (s->cmos_data[RTC_HOURS] & 0x80)) {
+        tm->tm_hour += 12;
+    }
+    tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]);
+    tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
+    tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
+    tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + 100;
+}
+
+static void rtc_copy_date(RTCState *s)
+{
+    const struct tm *tm = &s->current_tm;
+
+    s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);
+    s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);
+    if (s->cmos_data[RTC_REG_B] & 0x02) {
+        /* 24 hour format */
+        s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour);
+    } else {
+        /* 12 hour format */
+        s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12);
+        if (tm->tm_hour >= 12)
+            s->cmos_data[RTC_HOURS] |= 0x80;
+    }
+    s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday);
+    s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday);
+    s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1);
+    s->cmos_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100);
+}
+
+/* month is between 0 and 11. */
+static int get_days_in_month(int month, int year)
+{
+    static const int days_tab[12] = {
+        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+    };
+    int d;
+    if ((unsigned )month >= 12)
+        return 31;
+    d = days_tab[month];
+    if (month == 1) {
+        if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
+            d++;
+    }
+    return d;
+}
+
+/* update 'tm' to the next second */
+static void rtc_next_second(struct tm *tm)
+{
+    int days_in_month;
+
+    tm->tm_sec++;
+    if ((unsigned)tm->tm_sec >= 60) {
+        tm->tm_sec = 0;
+        tm->tm_min++;
+        if ((unsigned)tm->tm_min >= 60) {
+            tm->tm_min = 0;
+            tm->tm_hour++;
+            if ((unsigned)tm->tm_hour >= 24) {
+                tm->tm_hour = 0;
+                /* next day */
+                tm->tm_wday++;
+                if ((unsigned)tm->tm_wday >= 7)
+                    tm->tm_wday = 0;
+                days_in_month = get_days_in_month(tm->tm_mon,
+                                                  tm->tm_year + 1900);
+                tm->tm_mday++;
+                if (tm->tm_mday < 1) {
+                    tm->tm_mday = 1;
+                } else if (tm->tm_mday > days_in_month) {
+                    tm->tm_mday = 1;
+                    tm->tm_mon++;
+                    if (tm->tm_mon >= 12) {
+                        tm->tm_mon = 0;
+                        tm->tm_year++;
+                    }
+                }
+            }
+        }
+    }
+}
+
+
+static void rtc_update_second(void *opaque)
+{
+    RTCState *s = opaque;
+    int64_t delay;
+
+    /* if the oscillator is not in normal operation, we do not update */
+    if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
+        s->next_second_time += ticks_per_sec;
+        qemu_mod_timer(s->second_timer, s->next_second_time);
+    } else {
+        rtc_next_second(&s->current_tm);
+
+        if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
+            /* update in progress bit */
+            s->cmos_data[RTC_REG_A] |= REG_A_UIP;
+        }
+        /* should be 244 us = 8 / 32768 seconds, but currently the
+           timers do not have the necessary resolution. */
+        delay = (ticks_per_sec * 1) / 100;
+        if (delay < 1)
+            delay = 1;
+        qemu_mod_timer(s->second_timer2,
+                       s->next_second_time + delay);
+    }
+}
+
+static void rtc_update_second2(void *opaque)
+{
+    RTCState *s = opaque;
+
+    if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
+        rtc_copy_date(s);
+    }
+
+    /* check alarm */
+    if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
+        if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
+             s->cmos_data[RTC_SECONDS_ALARM] == s->current_tm.tm_sec) &&
+            ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
+             s->cmos_data[RTC_MINUTES_ALARM] == s->current_tm.tm_mon) &&
+            ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
+             s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
+
+            s->cmos_data[RTC_REG_C] |= 0xa0;
+            qemu_irq_raise(s->irq);
+        }
+    }
+
+    /* update ended interrupt */
+    if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
+        s->cmos_data[RTC_REG_C] |= 0x90;
+        qemu_irq_raise(s->irq);
+    }
+
+    /* clear update in progress bit */
+    s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
+
+    s->next_second_time += ticks_per_sec;
+    qemu_mod_timer(s->second_timer, s->next_second_time);
+}
+#endif
+
+uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
+{
+    RTCState *s = opaque;
+    int ret;
+    if ((addr & 1) == 0) {
+        return 0xff;
+    } else {
+        switch(s->cmos_index) {
+        case RTC_SECONDS:
+         ret = s->cmos_data[s->cmos_index]++;
+        case RTC_MINUTES:
+        case RTC_HOURS:
+        case RTC_DAY_OF_WEEK:
+        case RTC_DAY_OF_MONTH:
+        case RTC_MONTH:
+        case RTC_YEAR:
+            ret = s->cmos_data[s->cmos_index];
+            break;
+        case RTC_REG_A:
+            ret = s->cmos_data[s->cmos_index];
+            break;
+        case RTC_REG_C:
+            ret = s->cmos_data[s->cmos_index];
+            qemu_irq_lower(s->irq);
+            s->cmos_data[RTC_REG_C] = 0x00;
+            break;
+        default:
+            ret = s->cmos_data[s->cmos_index];
+            break;
+        }
+#ifdef DEBUG_CMOS
+        printf("cmos: read index=0x%02x val=0x%02x\n",
+               s->cmos_index, ret);
+#endif
+        return ret;
+    }
+}
+
+void rtc_set_memory(RTCState *s, int addr, int val)
+{
+    if (addr >= 0 && addr <= 127)
+        s->cmos_data[addr] = val;
+}
+
+#ifndef IOEMU
+void rtc_set_date(RTCState *s, const struct tm *tm)
+{
+    s->current_tm = *tm;
+    rtc_copy_date(s);
+}
+#endif
+
+/* PC cmos mappings */
+#define REG_IBM_CENTURY_BYTE        0x32
+#define REG_IBM_PS2_CENTURY_BYTE    0x37
+
+#ifndef IOEMU
+void rtc_set_date_from_host(RTCState *s)
+{
+    time_t ti;
+    struct tm *tm;
+    int val;
+
+    /* set the CMOS date */
+    if (rtc_start_date == -1) {
+        time(&ti);
+        if (rtc_utc)
+            tm = gmtime(&ti);
+        else
+            tm = localtime(&ti);
+    } else {
+        ti = rtc_start_date;
+        tm = gmtime(&ti);
+    }
+    rtc_set_date(s, tm);
+
+    val = to_bcd(s, (tm->tm_year / 100) + 19);
+    rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val);
+    rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val);
+}
+
+static void rtc_save(QEMUFile *f, void *opaque)
+{
+    RTCState *s = opaque;
+
+    qemu_put_buffer(f, s->cmos_data, 128);
+    qemu_put_8s(f, &s->cmos_index);
+
+    qemu_put_be32s(f, &s->current_tm.tm_sec);
+    qemu_put_be32s(f, &s->current_tm.tm_min);
+    qemu_put_be32s(f, &s->current_tm.tm_hour);
+    qemu_put_be32s(f, &s->current_tm.tm_wday);
+    qemu_put_be32s(f, &s->current_tm.tm_mday);
+    qemu_put_be32s(f, &s->current_tm.tm_mon);
+    qemu_put_be32s(f, &s->current_tm.tm_year);
+
+    qemu_put_timer(f, s->periodic_timer);
+    qemu_put_be64s(f, &s->next_periodic_time);
+
+    qemu_put_be64s(f, &s->next_second_time);
+    qemu_put_timer(f, s->second_timer);
+    qemu_put_timer(f, s->second_timer2);
+}
+
+static int rtc_load(QEMUFile *f, void *opaque, int version_id)
+{
+    RTCState *s = opaque;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    qemu_get_buffer(f, s->cmos_data, 128);
+    qemu_get_8s(f, &s->cmos_index);
+
+    qemu_get_be32s(f, &s->current_tm.tm_sec);
+    qemu_get_be32s(f, &s->current_tm.tm_min);
+    qemu_get_be32s(f, &s->current_tm.tm_hour);
+    qemu_get_be32s(f, &s->current_tm.tm_wday);
+    qemu_get_be32s(f, &s->current_tm.tm_mday);
+    qemu_get_be32s(f, &s->current_tm.tm_mon);
+    qemu_get_be32s(f, &s->current_tm.tm_year);
+
+    qemu_get_timer(f, s->periodic_timer);
+    qemu_get_be64s(f, &s->next_periodic_time);
+
+    qemu_get_be64s(f, &s->next_second_time);
+    qemu_get_timer(f, s->second_timer);
+    qemu_get_timer(f, s->second_timer2);
+    return 0;
+}
+#endif
+
+RTCState *rtc_init(int base, qemu_irq irq)
+{
+    RTCState *s;
+
+    s = qemu_mallocz(sizeof(RTCState));
+    if (!s)
+        return NULL;
+
+    s->irq = irq;
+    s->cmos_data[RTC_REG_A] = 0x26;
+    s->cmos_data[RTC_REG_B] = 0x02;
+    s->cmos_data[RTC_REG_C] = 0x00;
+    s->cmos_data[RTC_REG_D] = 0x80;
+
+#ifndef IOEMU
+    rtc_set_date_from_host(s);
+
+    s->periodic_timer = qemu_new_timer(vm_clock,
+                                       rtc_periodic_timer, s);
+    s->second_timer = qemu_new_timer(vm_clock,
+                                     rtc_update_second, s);
+    s->second_timer2 = qemu_new_timer(vm_clock,
+                                      rtc_update_second2, s);
+
+    s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 
100;
+    qemu_mod_timer(s->second_timer2, s->next_second_time);
+#endif
+
+    register_ioport_write(base, 2, 1, cmos_ioport_write, s);
+    register_ioport_read(base, 2, 1, cmos_ioport_read, s);
+
+    register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
+
+    return s;
+}
+
+#ifndef IOEMU
+/* Memory mapped interface */
+uint32_t cmos_mm_readb (void *opaque, target_phys_addr_t addr)
+{
+    RTCState *s = opaque;
+
+    return cmos_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFF;
+}
+
+void cmos_mm_writeb (void *opaque,
+                     target_phys_addr_t addr, uint32_t value)
+{
+    RTCState *s = opaque;
+
+    cmos_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFF);
+}
+
+uint32_t cmos_mm_readw (void *opaque, target_phys_addr_t addr)
+{
+    RTCState *s = opaque;
+    uint32_t val;
+
+    val = cmos_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF;
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = bswap16(val);
+#endif
+    return val;
+}
+
+void cmos_mm_writew (void *opaque,
+                     target_phys_addr_t addr, uint32_t value)
+{
+    RTCState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+    value = bswap16(value);
+#endif
+    cmos_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFFFF);
+}
+
+uint32_t cmos_mm_readl (void *opaque, target_phys_addr_t addr)
+{
+    RTCState *s = opaque;
+    uint32_t val;
+
+    val = cmos_ioport_read(s, (addr - s->base) >> s->it_shift);
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = bswap32(val);
+#endif
+    return val;
+}
+
+void cmos_mm_writel (void *opaque,
+                     target_phys_addr_t addr, uint32_t value)
+{
+    RTCState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+    value = bswap32(value);
+#endif
+    cmos_ioport_write(s, (addr - s->base) >> s->it_shift, value);
+}
+
+static CPUReadMemoryFunc *rtc_mm_read[] = {
+    &cmos_mm_readb,
+    &cmos_mm_readw,
+    &cmos_mm_readl,
+};
+
+static CPUWriteMemoryFunc *rtc_mm_write[] = {
+    &cmos_mm_writeb,
+    &cmos_mm_writew,
+    &cmos_mm_writel,
+};
+
+RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq)
+{
+    RTCState *s;
+    int io_memory;
+
+    s = qemu_mallocz(sizeof(RTCState));
+    if (!s)
+        return NULL;
+
+    s->irq = irq;
+    s->cmos_data[RTC_REG_A] = 0x26;
+    s->cmos_data[RTC_REG_B] = 0x02;
+    s->cmos_data[RTC_REG_C] = 0x00;
+    s->cmos_data[RTC_REG_D] = 0x80;
+    s->base = base;
+
+    rtc_set_date_from_host(s);
+
+    s->periodic_timer = qemu_new_timer(vm_clock,
+                                       rtc_periodic_timer, s);
+    s->second_timer = qemu_new_timer(vm_clock,
+                                     rtc_update_second, s);
+    s->second_timer2 = qemu_new_timer(vm_clock,
+                                      rtc_update_second2, s);
+
+    s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 
100;
+    qemu_mod_timer(s->second_timer2, s->next_second_time);
+
+    io_memory = cpu_register_io_memory(0, rtc_mm_read, rtc_mm_write, s);
+    cpu_register_physical_memory(base, 2 << it_shift, io_memory);
+
+    register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
+    return s;
+}
+#endif
diff -r 092232fa1fbd extras/stubfw/ioemu/monitor.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/ioemu/monitor.c     Sun Nov 18 08:08:19 2007 +0100
@@ -0,0 +1,1956 @@
+/*
+ * QEMU monitor
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+#include "ctype.h"
+//#include "disas.h"
+
+//#define DEBUG
+//#define DEBUG_COMPLETION
+
+#ifndef offsetof
+#define offsetof(type, field) ((size_t) &((type *)0)->field)
+#endif
+
+/*
+ * Supported types:
+ *
+ * 'F'          filename
+ * 'B'          block device name
+ * 's'          string (accept optional quote)
+ * 'i'          32 bit integer
+ * 'l'          target long (32 or 64 bit)
+ * '/'          optional gdb-like print format (like "/10x")
+ *
+ * '?'          optional type (for 'F', 's' and 'i')
+ *
+ */
+
+typedef void (*cmd_handler)(void);
+typedef struct term_cmd_t {
+    const char *name;
+    const char *args_type;
+    void (*handler)(void);
+    const char *params;
+    const char *help;
+} term_cmd_t;
+
+#define MAX_MON 4
+static CharDriverState *monitor_hd[MAX_MON];
+static int hide_banner;
+
+static term_cmd_t term_cmds[];
+static term_cmd_t info_cmds[];
+
+static char term_outbuf[1024];
+static int term_outbuf_index;
+
+static void monitor_start_input(void);
+
+void term_flush(void)
+{
+    int i;
+    if (term_outbuf_index > 0) {
+        for (i = 0; i < MAX_MON; i++)
+            if (monitor_hd[i] && monitor_hd[i]->focus == 0)
+                qemu_chr_write(monitor_hd[i], term_outbuf, term_outbuf_index);
+        term_outbuf_index = 0;
+    }
+}
+
+/* flush at every end of line or if the buffer is full */
+void term_puts(const char *str)
+{
+    int c;
+    for(;;) {
+        c = *str++;
+        if (c == '\0')
+            break;
+        if (c == '\n')
+            term_outbuf[term_outbuf_index++] = '\r';
+        term_outbuf[term_outbuf_index++] = c;
+        if (term_outbuf_index >= (sizeof(term_outbuf) - 1) ||
+            c == '\n')
+            term_flush();
+    }
+}
+
+void term_vprintf(const char *fmt, va_list ap)
+{
+    char buf[4096];
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+    term_puts(buf);
+}
+
+void term_printf(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    term_vprintf(fmt, ap);
+    va_end(ap);
+}
+
+void term_print_filename(const char *filename)
+{
+    int i;
+
+    for (i = 0; filename[i]; i++) {
+       switch (filename[i]) {
+       case ' ':
+       case '"':
+       case '\\':
+           term_printf("\\%c", filename[i]);
+           break;
+       case '\t':
+           term_printf("\\t");
+           break;
+       case '\r':
+           term_printf("\\r");
+           break;
+       case '\n':
+           term_printf("\\n");
+           break;
+       default:
+           term_printf("%c", filename[i]);
+           break;
+       }
+    }
+}
+
+static int compare_cmd(const char *name, const char *list)
+{
+    const char *p, *pstart;
+    int len;
+    len = strlen(name);
+    p = list;
+    for(;;) {
+        pstart = p;
+        p = strchr(p, '|');
+        if (!p)
+            p = pstart + strlen(pstart);
+        if ((p - pstart) == len && !memcmp(pstart, name, len))
+            return 1;
+        if (*p == '\0')
+            break;
+        p++;
+    }
+    return 0;
+}
+
+static void help_cmd1(term_cmd_t *cmds, const char *prefix, const char *name)
+{
+    term_cmd_t *cmd;
+
+    for(cmd = cmds; cmd->name != NULL; cmd++) {
+        if (!name || !strcmp(name, cmd->name))
+            term_printf("%s%s %s -- %s\n", prefix, cmd->name, cmd->params, 
cmd->help);
+    }
+}
+
+static void help_cmd(const char *name)
+{
+    if (name && !strcmp(name, "info")) {
+        help_cmd1(info_cmds, "info ", NULL);
+    } else {
+        help_cmd1(term_cmds, "", name);
+    }
+}
+
+static void do_help(const char *name)
+{
+    help_cmd(name);
+}
+
+static void do_commit(const char *device)
+{
+    int i, all_devices;
+
+    all_devices = !strcmp(device, "all");
+    for (i = 0; i < MAX_DISKS; i++) {
+        if (bs_table[i]) {
+            if (all_devices ||
+                !strcmp(bdrv_get_device_name(bs_table[i]), device))
+                bdrv_commit(bs_table[i]);
+        }
+    }
+    if (mtd_bdrv)
+        if (all_devices || !strcmp(bdrv_get_device_name(mtd_bdrv), device))
+            bdrv_commit(mtd_bdrv);
+}
+
+static void do_info(const char *item)
+{
+    term_cmd_t *cmd;
+
+    if (!item)
+        goto help;
+    for(cmd = info_cmds; cmd->name != NULL; cmd++) {
+        if (compare_cmd(item, cmd->name))
+            goto found;
+    }
+ help:
+    help_cmd("info");
+    return;
+ found:
+    cmd->handler();
+}
+
+static void do_info_version(void)
+{
+  term_printf("%s\n", QEMU_VERSION);
+}
+
+
+static void do_info_block(void)
+{
+    bdrv_info();
+}
+
+
+static void do_info_history (void)
+{
+    int i;
+    const char *str;
+
+    i = 0;
+    for(;;) {
+        str = readline_get_history(i);
+        if (!str)
+            break;
+       term_printf("%d: '%s'\n", i, str);
+        i++;
+    }
+}
+
+#if defined(TARGET_PPC)
+/* XXX: not implemented in other targets */
+static void do_info_cpu_stats (void)
+{
+    CPUState *env;
+
+    env = mon_get_cpu();
+    cpu_dump_statistics(env, NULL, &monitor_fprintf, 0);
+}
+#endif
+
+static void do_quit(void)
+{
+    exit();
+}
+
+static int eject_device(BlockDriverState *bs, int force)
+{
+    if (bdrv_is_inserted(bs)) {
+        if (!force) {
+            if (!bdrv_is_removable(bs)) {
+                term_printf("device is not removable\n");
+                return -1;
+            }
+            if (bdrv_is_locked(bs)) {
+                term_printf("device is locked\n");
+                return -1;
+            }
+        }
+        bdrv_close(bs);
+    }
+    return 0;
+}
+
+static void do_eject(int force, const char *filename)
+{
+    BlockDriverState *bs;
+
+    bs = bdrv_find(filename);
+    if (!bs) {
+        term_printf("device not found\n");
+        return;
+    }
+    eject_device(bs, force);
+}
+
+
+static void term_printc(int c)
+{
+    term_printf("'");
+    switch(c) {
+    case '\'':
+        term_printf("\\'");
+        break;
+    case '\\':
+        term_printf("\\\\");
+        break;
+    case '\n':
+        term_printf("\\n");
+        break;
+    case '\r':
+        term_printf("\\r");
+        break;
+    default:
+        if (c >= 32 && c <= 126) {
+            term_printf("%c", c);
+        } else {
+            term_printf("\\x%02x", c);
+        }
+        break;
+    }
+    term_printf("'");
+}
+
+static void memory_dump(int count, int format, int wsize,
+                        target_phys_addr_t addr, int is_physical)
+{
+    int nb_per_line, l, line_size, i, max_digits, len;
+    uint8_t buf[16];
+    uint64_t v;
+
+#if 0
+    if (format == 'i') {
+       CPUState *env;
+        int flags;
+        flags = 0;
+        env = mon_get_cpu();
+        if (!env && !is_physical)
+            return;
+#ifdef TARGET_I386
+        if (wsize == 2) {
+            flags = 1;
+        } else if (wsize == 4) {
+            flags = 0;
+        } else {
+            /* as default we use the current CS size */
+            flags = 0;
+            if (env) {
+#ifdef TARGET_X86_64
+                if ((env->efer & MSR_EFER_LMA) &&
+                    (env->segs[R_CS].flags & DESC_L_MASK))
+                    flags = 2;
+                else
+#endif
+                if (!(env->segs[R_CS].flags & DESC_B_MASK))
+                    flags = 1;
+            }
+        }
+#endif
+        monitor_disas(env, addr, count, is_physical, flags);
+        return;
+    }
+#endif
+
+    len = wsize * count;
+    if (wsize == 1)
+        line_size = 8;
+    else
+        line_size = 16;
+    nb_per_line = line_size / wsize;
+    max_digits = 0;
+
+    switch(format) {
+    case 'o':
+        max_digits = (wsize * 8 + 2) / 3;
+        break;
+    default:
+    case 'x':
+        max_digits = (wsize * 8) / 4;
+        break;
+    case 'u':
+    case 'd':
+        max_digits = (wsize * 8 * 10 + 32) / 33;
+        break;
+    case 'c':
+        wsize = 1;
+        break;
+    }
+
+    while (len > 0) {
+        if (is_physical)
+            term_printf(TARGET_FMT_plx ":", addr);
+        else
+            term_printf(TARGET_FMT_lx ":", (target_ulong)addr);
+        l = len;
+        if (l > line_size)
+            l = line_size;
+       cpu_physical_memory_rw(addr, buf, l, 0);
+        i = 0;
+        while (i < l) {
+            switch(wsize) {
+            default:
+            case 1:
+                v = ldub_raw(buf + i);
+                break;
+            case 2:
+                v = lduw_raw(buf + i);
+                break;
+            case 4:
+                v = (uint32_t)ldl_raw(buf + i);
+                break;
+            case 8:
+                v = ldq_raw(buf + i);
+                break;
+            }
+            term_printf(" ");
+            switch(format) {
+            case 'o':
+                term_printf("%#*" PRIo64, max_digits, v);
+                break;
+            case 'x':
+                term_printf("0x%0*" PRIx64, max_digits, v);
+                break;
+            case 'u':
+                term_printf("%*" PRIu64, max_digits, v);
+                break;
+            case 'd':
+                term_printf("%*" PRId64, max_digits, v);
+                break;
+            case 'c':
+                term_printc(v);
+                break;
+            }
+            i += wsize;
+        }
+        term_printf("\n");
+        addr += l;
+        len -= l;
+    }
+}
+
+#if TARGET_LONG_BITS == 64
+#define GET_TLONG(h, l) (((uint64_t)(h) << 32) | (l))
+#else
+#define GET_TLONG(h, l) (l)
+#endif
+
+static void do_memory_dump(int count, int format, int size,
+                           uint32_t addrh, uint32_t addrl)
+{
+    target_long addr = GET_TLONG(addrh, addrl);
+    memory_dump(count, format, size, addr, 0);
+}
+
+#if TARGET_PHYS_ADDR_BITS > 32
+#define GET_TPHYSADDR(h, l) (((uint64_t)(h) << 32) | (l))
+#else
+#define GET_TPHYSADDR(h, l) (l)
+#endif
+
+static void do_physical_memory_dump(int count, int format, int size,
+                                    uint32_t addrh, uint32_t addrl)
+
+{
+    target_phys_addr_t addr = GET_TPHYSADDR(addrh, addrl);
+    memory_dump(count, format, size, addr, 1);
+}
+
+static void do_print(int count, int format, int size, unsigned int valh, 
unsigned int vall)
+{
+    target_phys_addr_t val = GET_TPHYSADDR(valh, vall);
+#if TARGET_PHYS_ADDR_BITS == 32
+    switch(format) {
+    case 'o':
+        term_printf("%#o", val);
+        break;
+    case 'x':
+        term_printf("%#x", val);
+        break;
+    case 'u':
+        term_printf("%u", val);
+        break;
+    default:
+    case 'd':
+        term_printf("%d", val);
+        break;
+    case 'c':
+        term_printc(val);
+        break;
+    }
+#else
+    switch(format) {
+    case 'o':
+        term_printf("%#" PRIo64, val);
+        break;
+    case 'x':
+        term_printf("%#" PRIx64, val);
+        break;
+    case 'u':
+        term_printf("%" PRIu64, val);
+        break;
+    default:
+    case 'd':
+        term_printf("%" PRId64, val);
+        break;
+    case 'c':
+        term_printc(val);
+        break;
+    }
+#endif
+    term_printf("\n");
+}
+
+static void do_sum(uint32_t start, uint32_t size)
+{
+    uint32_t addr;
+    uint8_t buf[1];
+    uint16_t sum;
+
+    sum = 0;
+    for(addr = start; addr < (start + size); addr++) {
+        cpu_physical_memory_rw(addr, buf, 1, 0);
+        /* BSD sum algorithm ('sum' Unix command) */
+        sum = (sum >> 1) | (sum << 15);
+        sum += buf[0];
+    }
+    term_printf("%05d\n", sum);
+}
+
+static void do_ioport_read(int count, int format, int size, int addr, int 
has_index, int index)
+{
+    uint32_t val;
+    int suffix;
+
+    if (has_index) {
+        cpu_outb(addr & 0xffff, index & 0xff);
+        addr++;
+    }
+    addr &= 0xffff;
+
+    switch(size) {
+    default:
+    case 1:
+        val = cpu_inb(addr);
+        suffix = 'b';
+        break;
+    case 2:
+        val = cpu_inw(addr);
+        suffix = 'w';
+        break;
+    case 4:
+        val = cpu_inl(addr);
+        suffix = 'l';
+        break;
+    }
+    term_printf("port%c[0x%04x] = %#0*x\n",
+                suffix, addr, size * 2, val);
+}
+
+#if defined(TARGET_I386)
+static void print_pte(uint32_t addr, uint32_t pte, uint32_t mask)
+{
+    term_printf("%08x: %08x %c%c%c%c%c%c%c%c\n",
+                addr,
+                pte & mask,
+                pte & PG_GLOBAL_MASK ? 'G' : '-',
+                pte & PG_PSE_MASK ? 'P' : '-',
+                pte & PG_DIRTY_MASK ? 'D' : '-',
+                pte & PG_ACCESSED_MASK ? 'A' : '-',
+                pte & PG_PCD_MASK ? 'C' : '-',
+                pte & PG_PWT_MASK ? 'T' : '-',
+                pte & PG_USER_MASK ? 'U' : '-',
+                pte & PG_RW_MASK ? 'W' : '-');
+}
+
+static void tlb_info(void)
+{
+    CPUState *env;
+    int l1, l2;
+    uint32_t pgd, pde, pte;
+
+    env = mon_get_cpu();
+    if (!env)
+        return;
+
+    if (!(env->cr[0] & CR0_PG_MASK)) {
+        term_printf("PG disabled\n");
+        return;
+    }
+    pgd = env->cr[3] & ~0xfff;
+    for(l1 = 0; l1 < 1024; l1++) {
+        cpu_physical_memory_read(pgd + l1 * 4, (uint8_t *)&pde, 4);
+        pde = le32_to_cpu(pde);
+        if (pde & PG_PRESENT_MASK) {
+            if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
+                print_pte((l1 << 22), pde, ~((1 << 20) - 1));
+            } else {
+                for(l2 = 0; l2 < 1024; l2++) {
+                    cpu_physical_memory_read((pde & ~0xfff) + l2 * 4,
+                                             (uint8_t *)&pte, 4);
+                    pte = le32_to_cpu(pte);
+                    if (pte & PG_PRESENT_MASK) {
+                        print_pte((l1 << 22) + (l2 << 12),
+                                  pte & ~PG_PSE_MASK,
+                                  ~0xfff);
+                    }
+                }
+            }
+        }
+    }
+}
+
+static void mem_print(uint32_t *pstart, int *plast_prot,
+                      uint32_t end, int prot)
+{
+    int prot1;
+    prot1 = *plast_prot;
+    if (prot != prot1) {
+        if (*pstart != -1) {
+            term_printf("%08x-%08x %08x %c%c%c\n",
+                        *pstart, end, end - *pstart,
+                        prot1 & PG_USER_MASK ? 'u' : '-',
+                        'r',
+                        prot1 & PG_RW_MASK ? 'w' : '-');
+        }
+        if (prot != 0)
+            *pstart = end;
+        else
+            *pstart = -1;
+        *plast_prot = prot;
+    }
+}
+
+static void mem_info(void)
+{
+    CPUState *env;
+    int l1, l2, prot, last_prot;
+    uint32_t pgd, pde, pte, start, end;
+
+    env = mon_get_cpu();
+    if (!env)
+        return;
+
+    if (!(env->cr[0] & CR0_PG_MASK)) {
+        term_printf("PG disabled\n");
+        return;
+    }
+    pgd = env->cr[3] & ~0xfff;
+    last_prot = 0;
+    start = -1;
+    for(l1 = 0; l1 < 1024; l1++) {
+        cpu_physical_memory_read(pgd + l1 * 4, (uint8_t *)&pde, 4);
+        pde = le32_to_cpu(pde);
+        end = l1 << 22;
+        if (pde & PG_PRESENT_MASK) {
+            if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
+                prot = pde & (PG_USER_MASK | PG_RW_MASK | PG_PRESENT_MASK);
+                mem_print(&start, &last_prot, end, prot);
+            } else {
+                for(l2 = 0; l2 < 1024; l2++) {
+                    cpu_physical_memory_read((pde & ~0xfff) + l2 * 4,
+                                             (uint8_t *)&pte, 4);
+                    pte = le32_to_cpu(pte);
+                    end = (l1 << 22) + (l2 << 12);
+                    if (pte & PG_PRESENT_MASK) {
+                        prot = pte & (PG_USER_MASK | PG_RW_MASK | 
PG_PRESENT_MASK);
+                    } else {
+                        prot = 0;
+                    }
+                    mem_print(&start, &last_prot, end, prot);
+                }
+            }
+        } else {
+            prot = 0;
+            mem_print(&start, &last_prot, end, prot);
+        }
+    }
+}
+#endif
+
+static void do_info_kqemu(void)
+{
+#ifdef USE_KQEMU
+    CPUState *env;
+    int val;
+    val = 0;
+    env = mon_get_cpu();
+    if (!env) {
+        term_printf("No cpu initialized yet");
+        return;
+    }
+    val = env->kqemu_enabled;
+    term_printf("kqemu support: ");
+    switch(val) {
+    default:
+    case 0:
+        term_printf("disabled\n");
+        break;
+    case 1:
+        term_printf("enabled for user code\n");
+        break;
+    case 2:
+        term_printf("enabled for user and kernel code\n");
+        break;
+    }
+#else
+    term_printf("kqemu support: not compiled\n");
+#endif
+}
+
+
+static term_cmd_t term_cmds[] = {
+    { "help|?", "s?", (cmd_handler)do_help,
+      "[cmd]", "show the help" },
+    { "commit", "s", (cmd_handler)do_commit,
+      "device|all", "commit changes to the disk images (if -snapshot is used) 
or backing files" },
+    { "info", "s?", (cmd_handler)do_info,
+      "subcommand", "show various information about the system state" },
+    { "q|quit", "", do_quit,
+      "", "quit the emulator" },
+    { "eject", "-fB", (cmd_handler)do_eject,
+      "[-f] device", "eject a removable medium (use -f to force it)" },
+    { "x", "/l", (cmd_handler)do_memory_dump,
+      "/fmt addr", "virtual memory dump starting at 'addr'", },
+    { "xp", "/l", (cmd_handler)do_physical_memory_dump,
+      "/fmt addr", "physical memory dump starting at 'addr'", },
+    { "p|print", "/l", (cmd_handler)do_print,
+      "/fmt expr", "print expression value (use $reg for CPU register 
access)", },
+    { "i", "/ii.", (cmd_handler)do_ioport_read,
+      "/fmt addr", "I/O port read" },
+
+    { "sum", "ii", (cmd_handler)do_sum,
+      "addr size", "compute the checksum of a memory region" },
+    { NULL, NULL, },
+};
+
+static term_cmd_t info_cmds[] = {
+    { "version", "", do_info_version,
+      "", "show the version of qemu" },
+#if 0
+    { "network", "", (cmd_handler)do_info_network,
+      "", "show the network state" },
+    { "block", "", (cmd_handler)do_info_block,
+      "", "show the block devices" },
+    { "registers", "", (cmd_handler)do_info_registers,
+      "", "show the cpu registers" },
+    { "cpus", "", (cmd_handler)do_info_cpus,
+      "", "show infos for each CPU" },
+#endif
+    { "history", "", (cmd_handler)do_info_history,
+      "", "show the command line history", },
+#if 0
+    { "irq", "", irq_info,
+      "", "show the interrupts statistics (if available)", },
+    { "pic", "", pic_info,
+      "", "show i8259 (PIC) state", },
+#endif
+    { "pci", "", pci_info,
+      "", "show PCI info", },
+#if defined(TARGET_I386)
+    { "tlb", "", tlb_info,
+      "", "show virtual to physical memory mappings", },
+    { "mem", "", mem_info,
+      "", "show the active virtual memory mappings", },
+#endif
+#if defined(TARGET_PPC)
+    { "cpustats", "", do_info_cpu_stats,
+      "", "show CPU statistics", },
+#endif
+#if defined(CONFIG_SLIRP)
+    { "slirp", "", do_info_slirp,
+      "", "show SLIRP statistics", },
+#endif
+    { NULL, NULL, },
+};
+
+/*******************************************************************/
+
+static const char *pch;
+//static jmp_buf expr_env;
+
+#define MD_TLONG 0
+#define MD_I32   1
+
+typedef struct MonitorDef {
+    const char *name;
+    int offset;
+    target_long (*get_value)(struct MonitorDef *md, int val);
+    int type;
+} MonitorDef;
+
+#if defined(TARGET_I386)
+static target_long monitor_get_pc (struct MonitorDef *md, int val)
+{
+    CPUState *env = mon_get_cpu();
+    if (!env)
+        return 0;
+    return env->eip + env->segs[R_CS].base;
+}
+#endif
+
+#if defined(TARGET_PPC)
+static target_long monitor_get_ccr (struct MonitorDef *md, int val)
+{
+    CPUState *env = mon_get_cpu();
+    unsigned int u;
+    int i;
+
+    if (!env)
+        return 0;
+
+    u = 0;
+    for (i = 0; i < 8; i++)
+       u |= env->crf[i] << (32 - (4 * i));
+
+    return u;
+}
+
+static target_long monitor_get_msr (struct MonitorDef *md, int val)
+{
+    CPUState *env = mon_get_cpu();
+    if (!env)
+        return 0;
+    return env->msr;
+}
+
+static target_long monitor_get_xer (struct MonitorDef *md, int val)
+{
+    CPUState *env = mon_get_cpu();
+    if (!env)
+        return 0;
+    return ppc_load_xer(env);
+}
+
+static target_long monitor_get_decr (struct MonitorDef *md, int val)
+{
+    CPUState *env = mon_get_cpu();
+    if (!env)
+        return 0;
+    return cpu_ppc_load_decr(env);
+}
+
+static target_long monitor_get_tbu (struct MonitorDef *md, int val)
+{
+    CPUState *env = mon_get_cpu();
+    if (!env)
+        return 0;
+    return cpu_ppc_load_tbu(env);
+}
+
+static target_long monitor_get_tbl (struct MonitorDef *md, int val)
+{
+    CPUState *env = mon_get_cpu();
+    if (!env)
+        return 0;
+    return cpu_ppc_load_tbl(env);
+}
+#endif
+
+#if defined(TARGET_SPARC)
+#ifndef TARGET_SPARC64
+static target_long monitor_get_psr (struct MonitorDef *md, int val)
+{
+    CPUState *env = mon_get_cpu();
+    if (!env)
+        return 0;
+    return GET_PSR(env);
+}
+#endif
+
+static target_long monitor_get_reg(struct MonitorDef *md, int val)
+{
+    CPUState *env = mon_get_cpu();
+    if (!env)
+        return 0;
+    return env->regwptr[val];
+}
+#endif
+
+static MonitorDef monitor_defs[] = {
+#ifdef TARGET_I386
+
+#define SEG(name, seg) \
+    { name, offsetof(CPUState, segs[seg].selector), NULL, MD_I32 },\
+    { name ".base", offsetof(CPUState, segs[seg].base) },\
+    { name ".limit", offsetof(CPUState, segs[seg].limit), NULL, MD_I32 },
+
+    { "eax", offsetof(CPUState, regs[0]) },
+    { "ecx", offsetof(CPUState, regs[1]) },
+    { "edx", offsetof(CPUState, regs[2]) },
+    { "ebx", offsetof(CPUState, regs[3]) },
+    { "esp|sp", offsetof(CPUState, regs[4]) },
+    { "ebp|fp", offsetof(CPUState, regs[5]) },
+    { "esi", offsetof(CPUState, regs[6]) },
+    { "edi", offsetof(CPUState, regs[7]) },
+#ifdef TARGET_X86_64
+    { "r8", offsetof(CPUState, regs[8]) },
+    { "r9", offsetof(CPUState, regs[9]) },
+    { "r10", offsetof(CPUState, regs[10]) },
+    { "r11", offsetof(CPUState, regs[11]) },
+    { "r12", offsetof(CPUState, regs[12]) },
+    { "r13", offsetof(CPUState, regs[13]) },
+    { "r14", offsetof(CPUState, regs[14]) },
+    { "r15", offsetof(CPUState, regs[15]) },
+#endif
+    { "eflags", offsetof(CPUState, eflags) },
+    { "eip", offsetof(CPUState, eip) },
+    SEG("cs", R_CS)
+    SEG("ds", R_DS)
+    SEG("es", R_ES)
+    SEG("ss", R_SS)
+    SEG("fs", R_FS)
+    SEG("gs", R_GS)
+    { "pc", 0, monitor_get_pc, },
+#elif defined(TARGET_PPC)
+    /* General purpose registers */
+    { "r0", offsetof(CPUState, gpr[0]) },
+    { "r1", offsetof(CPUState, gpr[1]) },
+    { "r2", offsetof(CPUState, gpr[2]) },
+    { "r3", offsetof(CPUState, gpr[3]) },
+    { "r4", offsetof(CPUState, gpr[4]) },
+    { "r5", offsetof(CPUState, gpr[5]) },
+    { "r6", offsetof(CPUState, gpr[6]) },
+    { "r7", offsetof(CPUState, gpr[7]) },
+    { "r8", offsetof(CPUState, gpr[8]) },
+    { "r9", offsetof(CPUState, gpr[9]) },
+    { "r10", offsetof(CPUState, gpr[10]) },
+    { "r11", offsetof(CPUState, gpr[11]) },
+    { "r12", offsetof(CPUState, gpr[12]) },
+    { "r13", offsetof(CPUState, gpr[13]) },
+    { "r14", offsetof(CPUState, gpr[14]) },
+    { "r15", offsetof(CPUState, gpr[15]) },
+    { "r16", offsetof(CPUState, gpr[16]) },
+    { "r17", offsetof(CPUState, gpr[17]) },
+    { "r18", offsetof(CPUState, gpr[18]) },
+    { "r19", offsetof(CPUState, gpr[19]) },
+    { "r20", offsetof(CPUState, gpr[20]) },
+    { "r21", offsetof(CPUState, gpr[21]) },
+    { "r22", offsetof(CPUState, gpr[22]) },
+    { "r23", offsetof(CPUState, gpr[23]) },
+    { "r24", offsetof(CPUState, gpr[24]) },
+    { "r25", offsetof(CPUState, gpr[25]) },
+    { "r26", offsetof(CPUState, gpr[26]) },
+    { "r27", offsetof(CPUState, gpr[27]) },
+    { "r28", offsetof(CPUState, gpr[28]) },
+    { "r29", offsetof(CPUState, gpr[29]) },
+    { "r30", offsetof(CPUState, gpr[30]) },
+    { "r31", offsetof(CPUState, gpr[31]) },
+    /* Floating point registers */
+    { "f0", offsetof(CPUState, fpr[0]) },
+    { "f1", offsetof(CPUState, fpr[1]) },
+    { "f2", offsetof(CPUState, fpr[2]) },
+    { "f3", offsetof(CPUState, fpr[3]) },
+    { "f4", offsetof(CPUState, fpr[4]) },
+    { "f5", offsetof(CPUState, fpr[5]) },
+    { "f6", offsetof(CPUState, fpr[6]) },
+    { "f7", offsetof(CPUState, fpr[7]) },
+    { "f8", offsetof(CPUState, fpr[8]) },
+    { "f9", offsetof(CPUState, fpr[9]) },
+    { "f10", offsetof(CPUState, fpr[10]) },
+    { "f11", offsetof(CPUState, fpr[11]) },
+    { "f12", offsetof(CPUState, fpr[12]) },
+    { "f13", offsetof(CPUState, fpr[13]) },
+    { "f14", offsetof(CPUState, fpr[14]) },
+    { "f15", offsetof(CPUState, fpr[15]) },
+    { "f16", offsetof(CPUState, fpr[16]) },
+    { "f17", offsetof(CPUState, fpr[17]) },
+    { "f18", offsetof(CPUState, fpr[18]) },
+    { "f19", offsetof(CPUState, fpr[19]) },
+    { "f20", offsetof(CPUState, fpr[20]) },
+    { "f21", offsetof(CPUState, fpr[21]) },
+    { "f22", offsetof(CPUState, fpr[22]) },
+    { "f23", offsetof(CPUState, fpr[23]) },
+    { "f24", offsetof(CPUState, fpr[24]) },
+    { "f25", offsetof(CPUState, fpr[25]) },
+    { "f26", offsetof(CPUState, fpr[26]) },
+    { "f27", offsetof(CPUState, fpr[27]) },
+    { "f28", offsetof(CPUState, fpr[28]) },
+    { "f29", offsetof(CPUState, fpr[29]) },
+    { "f30", offsetof(CPUState, fpr[30]) },
+    { "f31", offsetof(CPUState, fpr[31]) },
+    { "fpscr", offsetof(CPUState, fpscr) },
+    /* Next instruction pointer */
+    { "nip|pc", offsetof(CPUState, nip) },
+    { "lr", offsetof(CPUState, lr) },
+    { "ctr", offsetof(CPUState, ctr) },
+    { "decr", 0, &monitor_get_decr, },
+    { "ccr", 0, &monitor_get_ccr, },
+    /* Machine state register */
+    { "msr", 0, &monitor_get_msr, },
+    { "xer", 0, &monitor_get_xer, },
+    { "tbu", 0, &monitor_get_tbu, },
+    { "tbl", 0, &monitor_get_tbl, },
+#if defined(TARGET_PPC64)
+    /* Address space register */
+    { "asr", offsetof(CPUState, asr) },
+#endif
+    /* Segment registers */
+    { "sdr1", offsetof(CPUState, sdr1) },
+    { "sr0", offsetof(CPUState, sr[0]) },
+    { "sr1", offsetof(CPUState, sr[1]) },
+    { "sr2", offsetof(CPUState, sr[2]) },
+    { "sr3", offsetof(CPUState, sr[3]) },
+    { "sr4", offsetof(CPUState, sr[4]) },
+    { "sr5", offsetof(CPUState, sr[5]) },
+    { "sr6", offsetof(CPUState, sr[6]) },
+    { "sr7", offsetof(CPUState, sr[7]) },
+    { "sr8", offsetof(CPUState, sr[8]) },
+    { "sr9", offsetof(CPUState, sr[9]) },
+    { "sr10", offsetof(CPUState, sr[10]) },
+    { "sr11", offsetof(CPUState, sr[11]) },
+    { "sr12", offsetof(CPUState, sr[12]) },
+    { "sr13", offsetof(CPUState, sr[13]) },
+    { "sr14", offsetof(CPUState, sr[14]) },
+    { "sr15", offsetof(CPUState, sr[15]) },
+    /* Too lazy to put BATs and SPRs ... */
+#elif defined(TARGET_SPARC)
+    { "g0", offsetof(CPUState, gregs[0]) },
+    { "g1", offsetof(CPUState, gregs[1]) },
+    { "g2", offsetof(CPUState, gregs[2]) },
+    { "g3", offsetof(CPUState, gregs[3]) },
+    { "g4", offsetof(CPUState, gregs[4]) },
+    { "g5", offsetof(CPUState, gregs[5]) },
+    { "g6", offsetof(CPUState, gregs[6]) },
+    { "g7", offsetof(CPUState, gregs[7]) },
+    { "o0", 0, monitor_get_reg },
+    { "o1", 1, monitor_get_reg },
+    { "o2", 2, monitor_get_reg },
+    { "o3", 3, monitor_get_reg },
+    { "o4", 4, monitor_get_reg },
+    { "o5", 5, monitor_get_reg },
+    { "o6", 6, monitor_get_reg },
+    { "o7", 7, monitor_get_reg },
+    { "l0", 8, monitor_get_reg },
+    { "l1", 9, monitor_get_reg },
+    { "l2", 10, monitor_get_reg },
+    { "l3", 11, monitor_get_reg },
+    { "l4", 12, monitor_get_reg },
+    { "l5", 13, monitor_get_reg },
+    { "l6", 14, monitor_get_reg },
+    { "l7", 15, monitor_get_reg },
+    { "i0", 16, monitor_get_reg },
+    { "i1", 17, monitor_get_reg },
+    { "i2", 18, monitor_get_reg },
+    { "i3", 19, monitor_get_reg },
+    { "i4", 20, monitor_get_reg },
+    { "i5", 21, monitor_get_reg },
+    { "i6", 22, monitor_get_reg },
+    { "i7", 23, monitor_get_reg },
+    { "pc", offsetof(CPUState, pc) },
+    { "npc", offsetof(CPUState, npc) },
+    { "y", offsetof(CPUState, y) },
+#ifndef TARGET_SPARC64
+    { "psr", 0, &monitor_get_psr, },
+    { "wim", offsetof(CPUState, wim) },
+#endif
+    { "tbr", offsetof(CPUState, tbr) },
+    { "fsr", offsetof(CPUState, fsr) },
+    { "f0", offsetof(CPUState, fpr[0]) },
+    { "f1", offsetof(CPUState, fpr[1]) },
+    { "f2", offsetof(CPUState, fpr[2]) },
+    { "f3", offsetof(CPUState, fpr[3]) },
+    { "f4", offsetof(CPUState, fpr[4]) },
+    { "f5", offsetof(CPUState, fpr[5]) },
+    { "f6", offsetof(CPUState, fpr[6]) },
+    { "f7", offsetof(CPUState, fpr[7]) },
+    { "f8", offsetof(CPUState, fpr[8]) },
+    { "f9", offsetof(CPUState, fpr[9]) },
+    { "f10", offsetof(CPUState, fpr[10]) },
+    { "f11", offsetof(CPUState, fpr[11]) },
+    { "f12", offsetof(CPUState, fpr[12]) },
+    { "f13", offsetof(CPUState, fpr[13]) },
+    { "f14", offsetof(CPUState, fpr[14]) },
+    { "f15", offsetof(CPUState, fpr[15]) },
+    { "f16", offsetof(CPUState, fpr[16]) },
+    { "f17", offsetof(CPUState, fpr[17]) },
+    { "f18", offsetof(CPUState, fpr[18]) },
+    { "f19", offsetof(CPUState, fpr[19]) },
+    { "f20", offsetof(CPUState, fpr[20]) },
+    { "f21", offsetof(CPUState, fpr[21]) },
+    { "f22", offsetof(CPUState, fpr[22]) },
+    { "f23", offsetof(CPUState, fpr[23]) },
+    { "f24", offsetof(CPUState, fpr[24]) },
+    { "f25", offsetof(CPUState, fpr[25]) },
+    { "f26", offsetof(CPUState, fpr[26]) },
+    { "f27", offsetof(CPUState, fpr[27]) },
+    { "f28", offsetof(CPUState, fpr[28]) },
+    { "f29", offsetof(CPUState, fpr[29]) },
+    { "f30", offsetof(CPUState, fpr[30]) },
+    { "f31", offsetof(CPUState, fpr[31]) },
+#ifdef TARGET_SPARC64
+    { "f32", offsetof(CPUState, fpr[32]) },
+    { "f34", offsetof(CPUState, fpr[34]) },
+    { "f36", offsetof(CPUState, fpr[36]) },
+    { "f38", offsetof(CPUState, fpr[38]) },
+    { "f40", offsetof(CPUState, fpr[40]) },
+    { "f42", offsetof(CPUState, fpr[42]) },
+    { "f44", offsetof(CPUState, fpr[44]) },
+    { "f46", offsetof(CPUState, fpr[46]) },
+    { "f48", offsetof(CPUState, fpr[48]) },
+    { "f50", offsetof(CPUState, fpr[50]) },
+    { "f52", offsetof(CPUState, fpr[52]) },
+    { "f54", offsetof(CPUState, fpr[54]) },
+    { "f56", offsetof(CPUState, fpr[56]) },
+    { "f58", offsetof(CPUState, fpr[58]) },
+    { "f60", offsetof(CPUState, fpr[60]) },
+    { "f62", offsetof(CPUState, fpr[62]) },
+    { "asi", offsetof(CPUState, asi) },
+    { "pstate", offsetof(CPUState, pstate) },
+    { "cansave", offsetof(CPUState, cansave) },
+    { "canrestore", offsetof(CPUState, canrestore) },
+    { "otherwin", offsetof(CPUState, otherwin) },
+    { "wstate", offsetof(CPUState, wstate) },
+    { "cleanwin", offsetof(CPUState, cleanwin) },
+    { "fprs", offsetof(CPUState, fprs) },
+#endif
+#endif
+    { NULL },
+};
+
+static void expr_error(const char *fmt)
+{
+    term_printf(fmt);
+    term_printf("\n");
+    //longjmp(expr_env, 1);
+}
+
+/* return 0 if OK, -1 if not found, -2 if no CPU defined */
+static int get_monitor_def(target_long *pval, const char *name)
+{
+    MonitorDef *md;
+
+    for(md = monitor_defs; md->name != NULL; md++) {
+        if (compare_cmd(name, md->name)) {
+            if (md->get_value) {
+                *pval = md->get_value(md, md->offset);
+            } else {
+#if 0
+               void *ptr;
+                CPUState *env = mon_get_cpu();
+                if (!env)
+                    return -2;
+                ptr = (uint8_t *)env + md->offset;
+                switch(md->type) {
+                case MD_I32:
+                    *pval = *(int32_t *)ptr;
+                    break;
+                case MD_TLONG:
+                    *pval = *(target_long *)ptr;
+                    break;
+                default:
+                    *pval = 0;
+                    break;
+                }
+#else
+               return -2;
+#endif
+            }
+            return 0;
+        }
+    }
+    return -1;
+}
+
+static void next(void)
+{
+    if (pch != '\0') {
+        pch++;
+        while (*pch == ' ')
+            pch++;
+    }
+}
+
+static int64_t expr_sum(void);
+
+static int64_t expr_unary(void)
+{
+    int64_t n;
+    char *p;
+    int ret;
+
+    switch(*pch) {
+    case '+':
+        next();
+        n = expr_unary();
+        break;
+    case '-':
+        next();
+        n = -expr_unary();
+        break;
+    case '~':
+        next();
+        n = ~expr_unary();
+        break;
+    case '(':
+        next();
+        n = expr_sum();
+        if (*pch != ')') {
+            expr_error("')' expected");
+        }
+        next();
+        break;
+    case '\'':
+        pch++;
+        if (*pch == '\0')
+            expr_error("character constant expected");
+        n = *pch;
+        pch++;
+        if (*pch != '\'')
+            expr_error("missing terminating \' character");
+        next();
+        break;
+    case '$':
+        {
+            char buf[128], *q;
+            target_long reg;
+
+            pch++;
+            q = buf;
+            while ((*pch >= 'a' && *pch <= 'z') ||
+                   (*pch >= 'A' && *pch <= 'Z') ||
+                   (*pch >= '0' && *pch <= '9') ||
+                   *pch == '_' || *pch == '.') {
+                if ((q - buf) < sizeof(buf) - 1)
+                    *q++ = *pch;
+                pch++;
+            }
+            while (isspace(*pch))
+                pch++;
+            *q = 0;
+            ret = get_monitor_def(&reg, buf);
+            if (ret == -1)
+                expr_error("unknown register");
+            else if (ret == -2)
+                expr_error("no cpu defined");
+            n = reg;
+        }
+        break;
+    case '\0':
+        expr_error("unexpected end of expression");
+        n = 0;
+        break;
+    default:
+#if TARGET_PHYS_ADDR_BITS > 32
+        n = simple_strtoull(pch, &p, 0);
+#else
+        n = strtoul(pch, &p, 0);
+#endif
+        if (pch == p) {
+            expr_error("invalid char in expression");
+        }
+        pch = p;
+        while (isspace(*pch))
+            pch++;
+        break;
+    }
+    return n;
+}
+
+
+static int64_t expr_prod(void)
+{
+    int64_t val, val2;
+    int op;
+
+    val = expr_unary();
+    for(;;) {
+        op = *pch;
+        if (op != '*' && op != '/' && op != '%')
+            break;
+        next();
+        val2 = expr_unary();
+        switch(op) {
+        default:
+        case '*':
+            val *= val2;
+            break;
+        case '/':
+        case '%':
+            if (val2 == 0)
+                expr_error("division by zero");
+            if (op == '/')
+                val /= val2;
+            else
+                val %= val2;
+            break;
+        }
+    }
+    return val;
+}
+
+static int64_t expr_logic(void)
+{
+    int64_t val, val2;
+    int op;
+
+    val = expr_prod();
+    for(;;) {
+        op = *pch;
+        if (op != '&' && op != '|' && op != '^')
+            break;
+        next();
+        val2 = expr_prod();
+        switch(op) {
+        default:
+        case '&':
+            val &= val2;
+            break;
+        case '|':
+            val |= val2;
+            break;
+        case '^':
+            val ^= val2;
+            break;
+        }
+    }
+    return val;
+}
+
+static int64_t expr_sum(void)
+{
+    int64_t val, val2;
+    int op;
+
+    val = expr_logic();
+    for(;;) {
+        op = *pch;
+        if (op != '+' && op != '-')
+            break;
+        next();
+        val2 = expr_logic();
+        if (op == '+')
+            val += val2;
+        else
+            val -= val2;
+    }
+    return val;
+}
+
+static int get_expr(int64_t *pval, const char **pp)
+{
+    pch = *pp;
+#if 0
+    if (setjmp(expr_env)) {
+        *pp = pch;
+        return -1;
+    }
+#endif
+    while (isspace(*pch))
+        pch++;
+    *pval = expr_sum();
+    *pp = pch;
+    return 0;
+}
+
+static int get_str(char *buf, int buf_size, const char **pp)
+{
+    const char *p;
+    char *q;
+    int c;
+
+    q = buf;
+    p = *pp;
+    while (isspace(*p))
+        p++;
+    if (*p == '\0') {
+    fail:
+        *q = '\0';
+        *pp = p;
+        return -1;
+    }
+    if (*p == '\"') {
+        p++;
+        while (*p != '\0' && *p != '\"') {
+            if (*p == '\\') {
+                p++;
+                c = *p++;
+                switch(c) {
+                case 'n':
+                    c = '\n';
+                    break;
+                case 'r':
+                    c = '\r';
+                    break;
+                case '\\':
+                case '\'':
+                case '\"':
+                    break;
+                default:
+                    qemu_printf("unsupported escape code: '\\%c'\n", c);
+                    goto fail;
+                }
+                if ((q - buf) < buf_size - 1) {
+                    *q++ = c;
+                }
+            } else {
+                if ((q - buf) < buf_size - 1) {
+                    *q++ = *p;
+                }
+                p++;
+            }
+        }
+        if (*p != '\"') {
+            qemu_printf("unterminated string\n");
+            goto fail;
+        }
+        p++;
+    } else {
+        while (*p != '\0' && !isspace(*p)) {
+            if ((q - buf) < buf_size - 1) {
+                *q++ = *p;
+            }
+            p++;
+        }
+    }
+    *q = '\0';
+    *pp = p;
+    return 0;
+}
+
+static int default_fmt_format = 'x';
+static int default_fmt_size = 4;
+
+#define MAX_ARGS 16
+
+static void monitor_handle_command(const char *cmdline)
+{
+    const char *p, *pstart, *typestr;
+    char *q;
+    int c, nb_args, len, i, has_arg;
+    term_cmd_t *cmd;
+    char cmdname[256];
+    char buf[1024];
+    void *str_allocated[MAX_ARGS];
+    void *args[MAX_ARGS];
+
+#ifdef DEBUG
+    term_printf("command='%s'\n", cmdline);
+#endif
+
+    /* extract the command name */
+    p = cmdline;
+    q = cmdname;
+    while (isspace(*p))
+        p++;
+    if (*p == '\0')
+        return;
+    pstart = p;
+    while (*p != '\0' && *p != '/' && !isspace(*p))
+        p++;
+    len = p - pstart;
+    if (len > sizeof(cmdname) - 1)
+        len = sizeof(cmdname) - 1;
+    memcpy(cmdname, pstart, len);
+    cmdname[len] = '\0';
+
+    /* find the command */
+    for(cmd = term_cmds; cmd->name != NULL; cmd++) {
+        if (compare_cmd(cmdname, cmd->name))
+            goto found;
+    }
+    term_printf("unknown command: '%s'\n", cmdname);
+    return;
+ found:
+
+    for(i = 0; i < MAX_ARGS; i++)
+        str_allocated[i] = NULL;
+
+    /* parse the parameters */
+    typestr = cmd->args_type;
+    nb_args = 0;
+    for(;;) {
+        c = *typestr;
+        if (c == '\0')
+            break;
+        typestr++;
+        switch(c) {
+        case 'F':
+        case 'B':
+        case 's':
+            {
+                int ret;
+                char *str;
+
+                while (isspace(*p))
+                    p++;
+                if (*typestr == '?') {
+                    typestr++;
+                    if (*p == '\0') {
+                        /* no optional string: NULL argument */
+                        str = NULL;
+                        goto add_str;
+                    }
+                }
+                ret = get_str(buf, sizeof(buf), &p);
+                if (ret < 0) {
+                    switch(c) {
+                    case 'F':
+                        term_printf("%s: filename expected\n", cmdname);
+                        break;
+                    case 'B':
+                        term_printf("%s: block device name expected\n", 
cmdname);
+                        break;
+                    default:
+                        term_printf("%s: string expected\n", cmdname);
+                        break;
+                    }
+                    goto fail;
+                }
+                str = qemu_malloc(strlen(buf) + 1);
+                strcpy(str, buf);
+                str_allocated[nb_args] = str;
+            add_str:
+                if (nb_args >= MAX_ARGS) {
+                error_args:
+                    term_printf("%s: too many arguments\n", cmdname);
+                    goto fail;
+                }
+                args[nb_args++] = str;
+            }
+            break;
+        case '/':
+            {
+                int count, format, size;
+
+                while (isspace(*p))
+                    p++;
+                if (*p == '/') {
+                    /* format found */
+                    p++;
+                    count = 1;
+                    if (isdigit(*p)) {
+                        count = 0;
+                        while (isdigit(*p)) {
+                            count = count * 10 + (*p - '0');
+                            p++;
+                        }
+                    }
+                    size = -1;
+                    format = -1;
+                    for(;;) {
+                        switch(*p) {
+                        case 'o':
+                        case 'd':
+                        case 'u':
+                        case 'x':
+                        case 'i':
+                        case 'c':
+                            format = *p++;
+                            break;
+                        case 'b':
+                            size = 1;
+                            p++;
+                            break;
+                        case 'h':
+                            size = 2;
+                            p++;
+                            break;
+                        case 'w':
+                            size = 4;
+                            p++;
+                            break;
+                        case 'g':
+                        case 'L':
+                            size = 8;
+                            p++;
+                            break;
+                        default:
+                            goto next;
+                        }
+                    }
+                next:
+                    if (*p != '\0' && !isspace(*p)) {
+                        term_printf("invalid char in format: '%c'\n", *p);
+                        goto fail;
+                    }
+                    if (format < 0)
+                        format = default_fmt_format;
+                    if (format != 'i') {
+                        /* for 'i', not specifying a size gives -1 as size */
+                        if (size < 0)
+                            size = default_fmt_size;
+                    }
+                    default_fmt_size = size;
+                    default_fmt_format = format;
+                } else {
+                    count = 1;
+                    format = default_fmt_format;
+                    if (format != 'i') {
+                        size = default_fmt_size;
+                    } else {
+                        size = -1;
+                    }
+                }
+                if (nb_args + 3 > MAX_ARGS)
+                    goto error_args;
+                args[nb_args++] = (void*)(long)count;
+                args[nb_args++] = (void*)(long)format;
+                args[nb_args++] = (void*)(long)size;
+            }
+            break;
+        case 'i':
+        case 'l':
+            {
+                int64_t val;
+
+                while (isspace(*p))
+                    p++;
+                if (*typestr == '?' || *typestr == '.') {
+                    if (*typestr == '?') {
+                        if (*p == '\0')
+                            has_arg = 0;
+                        else
+                            has_arg = 1;
+                    } else {
+                        if (*p == '.') {
+                            p++;
+                            while (isspace(*p))
+                                p++;
+                            has_arg = 1;
+                        } else {
+                            has_arg = 0;
+                        }
+                    }
+                    typestr++;
+                    if (nb_args >= MAX_ARGS)
+                        goto error_args;
+                    args[nb_args++] = (void *)(long)has_arg;
+                    if (!has_arg) {
+                        if (nb_args >= MAX_ARGS)
+                            goto error_args;
+                        val = -1;
+                        goto add_num;
+                    }
+                }
+                if (get_expr(&val, &p))
+                    goto fail;
+            add_num:
+                if (c == 'i') {
+                    if (nb_args >= MAX_ARGS)
+                        goto error_args;
+                    args[nb_args++] = (void *)(long)val;
+                } else {
+                    if ((nb_args + 1) >= MAX_ARGS)
+                        goto error_args;
+#if TARGET_PHYS_ADDR_BITS > 32
+                    args[nb_args++] = (void *)(long)((val >> 32) & 0xffffffff);
+#else
+                    args[nb_args++] = (void *)0;
+#endif
+                    args[nb_args++] = (void *)(long)(val & 0xffffffff);
+                }
+            }
+            break;
+        case '-':
+            {
+                int has_option;
+                /* option */
+
+                c = *typestr++;
+                if (c == '\0')
+                    goto bad_type;
+                while (isspace(*p))
+                    p++;
+                has_option = 0;
+                if (*p == '-') {
+                    p++;
+                    if (*p != c) {
+                        term_printf("%s: unsupported option -%c\n",
+                                    cmdname, *p);
+                        goto fail;
+                    }
+                    p++;
+                    has_option = 1;
+                }
+                if (nb_args >= MAX_ARGS)
+                    goto error_args;
+                args[nb_args++] = (void *)(long)has_option;
+            }
+            break;
+        default:
+        bad_type:
+            term_printf("%s: unknown type '%c'\n", cmdname, c);
+            goto fail;
+        }
+    }
+    /* check that all arguments were parsed */
+    while (isspace(*p))
+        p++;
+    if (*p != '\0') {
+        term_printf("%s: extraneous characters at the end of line\n",
+                    cmdname);
+        goto fail;
+    }
+
+    switch(nb_args) {
+    case 0:
+        cmd->handler();
+        break;
+    case 1:
+        cmd->handler(args[0]);
+        break;
+    case 2:
+        cmd->handler(args[0], args[1]);
+        break;
+    case 3:
+        cmd->handler(args[0], args[1], args[2]);
+        break;
+    case 4:
+        cmd->handler(args[0], args[1], args[2], args[3]);
+        break;
+    case 5:
+        cmd->handler(args[0], args[1], args[2], args[3], args[4]);
+        break;
+    case 6:
+        cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5]);
+        break;
+    case 7:
+        cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5], 
args[6]);
+        break;
+    default:
+        term_printf("unsupported number of arguments: %d\n", nb_args);
+        goto fail;
+    }
+ fail:
+    for(i = 0; i < MAX_ARGS; i++)
+        qemu_free(str_allocated[i]);
+    return;
+}
+
+static void cmd_completion(const char *name, const char *list)
+{
+    const char *p, *pstart;
+    char cmd[128];
+    int len;
+
+    p = list;
+    for(;;) {
+        pstart = p;
+        p = strchr(p, '|');
+        if (!p)
+            p = pstart + strlen(pstart);
+        len = p - pstart;
+        if (len > sizeof(cmd) - 2)
+            len = sizeof(cmd) - 2;
+        memcpy(cmd, pstart, len);
+        cmd[len] = '\0';
+        if (name[0] == '\0' || !strncmp(name, cmd, strlen(name))) {
+            add_completion(cmd);
+        }
+        if (*p == '\0')
+            break;
+        p++;
+    }
+}
+
+
+static void block_completion_it(void *opaque, const char *name)
+{
+    const char *input = opaque;
+
+    if (input[0] == '\0' ||
+        !strncmp(name, (char *)input, strlen(input))) {
+        add_completion(name);
+    }
+}
+
+/* NOTE: this parser is an approximate form of the real command parser */
+static void parse_cmdline(const char *cmdline,
+                         int *pnb_args, char **args)
+{
+    const char *p;
+    int nb_args, ret;
+    char buf[1024];
+
+    p = cmdline;
+    nb_args = 0;
+    for(;;) {
+        while (isspace(*p))
+            p++;
+        if (*p == '\0')
+            break;
+        if (nb_args >= MAX_ARGS)
+            break;
+        ret = get_str(buf, sizeof(buf), &p);
+        args[nb_args] = qemu_strdup(buf);
+        nb_args++;
+        if (ret < 0)
+            break;
+    }
+    *pnb_args = nb_args;
+}
+
+void readline_find_completion(const char *cmdline)
+{
+    const char *cmdname;
+    char *args[MAX_ARGS];
+    int nb_args, i, len;
+    const char *ptype, *str;
+    term_cmd_t *cmd;
+    const KeyDef *key;
+
+    parse_cmdline(cmdline, &nb_args, args);
+#ifdef DEBUG_COMPLETION
+    for(i = 0; i < nb_args; i++) {
+        term_printf("arg%d = '%s'\n", i, (char *)args[i]);
+    }
+#endif
+
+    /* if the line ends with a space, it means we want to complete the
+       next arg */
+    len = strlen(cmdline);
+    if (len > 0 && isspace(cmdline[len - 1])) {
+        if (nb_args >= MAX_ARGS)
+            return;
+        args[nb_args++] = qemu_strdup("");
+    }
+    if (nb_args <= 1) {
+        /* command completion */
+        if (nb_args == 0)
+            cmdname = "";
+        else
+            cmdname = args[0];
+        completion_index = strlen(cmdname);
+        for(cmd = term_cmds; cmd->name != NULL; cmd++) {
+            cmd_completion(cmdname, cmd->name);
+        }
+    } else {
+        /* find the command */
+        for(cmd = term_cmds; cmd->name != NULL; cmd++) {
+            if (compare_cmd(args[0], cmd->name))
+                goto found;
+        }
+        return;
+    found:
+        ptype = cmd->args_type;
+        for(i = 0; i < nb_args - 2; i++) {
+            if (*ptype != '\0') {
+                ptype++;
+                while (*ptype == '?')
+                    ptype++;
+            }
+        }
+        str = args[nb_args - 1];
+        switch(*ptype) {
+        case 'B':
+            /* block device name completion */
+            completion_index = strlen(str);
+            bdrv_iterate(block_completion_it, (void *)str);
+            break;
+        case 's':
+            /* XXX: more generic ? */
+            if (!strcmp(cmd->name, "info")) {
+                completion_index = strlen(str);
+                for(cmd = info_cmds; cmd->name != NULL; cmd++) {
+                    cmd_completion(str, cmd->name);
+                }
+            } else if (!strcmp(cmd->name, "sendkey")) {
+                completion_index = strlen(str);
+                for(key = key_defs; key->name != NULL; key++) {
+                    cmd_completion(str, key->name);
+                }
+            }
+            break;
+        default:
+            break;
+        }
+    }
+    for(i = 0; i < nb_args; i++)
+        qemu_free(args[i]);
+}
+
+static int term_can_read(void *opaque)
+{
+    return 128;
+}
+
+static void term_read(void *opaque, const uint8_t *buf, int size)
+{
+    int i;
+    for(i = 0; i < size; i++)
+        readline_handle_byte(buf[i]);
+}
+
+static void monitor_start_input(void);
+
+static void monitor_handle_command1(void *opaque, const char *cmdline)
+{
+    monitor_handle_command(cmdline);
+    monitor_start_input();
+}
+
+static void monitor_start_input(void)
+{
+    readline_start("(qemu) ", 0, monitor_handle_command1, NULL);
+}
+
+static void term_event(void *opaque, int event)
+{
+    if (event != CHR_EVENT_RESET)
+       return;
+
+    if (!hide_banner)
+           term_printf("QEMU %s monitor - type 'help' for more information\n",
+                       QEMU_VERSION);
+    monitor_start_input();
+}
+
+static int is_first_init = 1;
+
+void monitor_init(CharDriverState *hd, int show_banner)
+{
+    int i;
+
+    if (is_first_init) {
+        for (i = 0; i < MAX_MON; i++) {
+            monitor_hd[i] = NULL;
+        }
+        is_first_init = 0;
+    }
+    for (i = 0; i < MAX_MON; i++) {
+        if (monitor_hd[i] == NULL) {
+            monitor_hd[i] = hd;
+            break;
+        }
+    }
+
+    hide_banner = !show_banner;
+
+    qemu_chr_add_handlers(hd, term_can_read, term_read, term_event, NULL);
+}
+
+/* XXX: use threads ? */
+/* modal monitor readline */
+static int monitor_readline_started;
+static char *monitor_readline_buf;
+static int monitor_readline_buf_size;
+
+static void monitor_readline_cb(void *opaque, const char *input)
+{
+    pstrcpy(monitor_readline_buf, monitor_readline_buf_size, input);
+    monitor_readline_started = 0;
+}
+
+void monitor_readline(const char *prompt, int is_password,
+                      char *buf, int buf_size)
+{
+    int i;
+
+    if (is_password) {
+        for (i = 0; i < MAX_MON; i++)
+            if (monitor_hd[i] && monitor_hd[i]->focus == 0)
+                qemu_chr_send_event(monitor_hd[i], CHR_EVENT_FOCUS);
+    }
+    readline_start(prompt, is_password, monitor_readline_cb, NULL);
+    monitor_readline_buf = buf;
+    monitor_readline_buf_size = buf_size;
+    monitor_readline_started = 1;
+    while (monitor_readline_started) {
+        main_loop_wait(10);
+    }
+}
diff -r 092232fa1fbd extras/stubfw/ioemu/pci.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/ioemu/pci.c Mon Nov 12 04:04:17 2007 +0100
@@ -0,0 +1,654 @@
+/*
+ * QEMU PCI bus manager
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+//#define DEBUG_PCI
+
+struct PCIBus {
+    int bus_num;
+    int devfn_min;
+    pci_set_irq_fn set_irq;
+    pci_map_irq_fn map_irq;
+    uint32_t config_reg; /* XXX: suppress */
+    /* low level pic */
+    SetIRQFunc *low_set_irq;
+    qemu_irq *irq_opaque;
+    PCIDevice *devices[256];
+    PCIDevice *parent_dev;
+    PCIBus *next;
+    /* The bus IRQ state is the logical OR of the connected devices.
+       Keep a count of the number of devices with raised IRQs.  */
+    int irq_count[];
+};
+
+static void pci_update_mappings(PCIDevice *d);
+static void pci_set_irq(void *opaque, int irq_num, int level);
+
+target_phys_addr_t pci_mem_base;
+static int pci_irq_index;
+static PCIBus *first_bus;
+
+PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
+                         qemu_irq *pic, int devfn_min, int nirq)
+{
+    PCIBus *bus;
+    bus = qemu_mallocz(sizeof(PCIBus) + (nirq * sizeof(int)));
+    bus->set_irq = set_irq;
+    bus->map_irq = map_irq;
+    bus->irq_opaque = pic;
+    bus->devfn_min = devfn_min;
+    first_bus = bus;
+    return bus;
+}
+
+PCIBus *pci_register_secondary_bus(PCIDevice *dev, pci_map_irq_fn map_irq)
+{
+    PCIBus *bus;
+    bus = qemu_mallocz(sizeof(PCIBus));
+    bus->map_irq = map_irq;
+    bus->parent_dev = dev;
+    bus->next = dev->bus->next;
+    dev->bus->next = bus;
+    return bus;
+}
+
+int pci_bus_num(PCIBus *s)
+{
+    return s->bus_num;
+}
+
+#ifndef IOEMU
+void pci_device_save(PCIDevice *s, QEMUFile *f)
+{
+    qemu_put_be32(f, 1); /* PCI device version */
+    qemu_put_buffer(f, s->config, 256);
+}
+
+int pci_device_load(PCIDevice *s, QEMUFile *f)
+{
+    uint32_t version_id;
+    version_id = qemu_get_be32(f);
+    if (version_id != 1)
+        return -EINVAL;
+    qemu_get_buffer(f, s->config, 256);
+    pci_update_mappings(s);
+    return 0;
+}
+#endif
+
+/* -1 for devfn means auto assign */
+PCIDevice *pci_register_device(PCIBus *bus, const char *name,
+                               int instance_size, int devfn,
+                               PCIConfigReadFunc *config_read,
+                               PCIConfigWriteFunc *config_write)
+{
+    PCIDevice *pci_dev;
+
+    if (pci_irq_index >= PCI_DEVICES_MAX)
+        return NULL;
+
+    if (devfn < 0) {
+        for(devfn = bus->devfn_min ; devfn < 256; devfn += 8) {
+            if (!bus->devices[devfn])
+                goto found;
+        }
+        return NULL;
+    found: ;
+    }
+    pci_dev = qemu_mallocz(instance_size);
+    if (!pci_dev)
+        return NULL;
+    pci_dev->bus = bus;
+    pci_dev->devfn = devfn;
+    pstrcpy(pci_dev->name, sizeof(pci_dev->name), name);
+    memset(pci_dev->irq_state, 0, sizeof(pci_dev->irq_state));
+
+    if (!config_read)
+        config_read = pci_default_read_config;
+    if (!config_write)
+        config_write = pci_default_write_config;
+    pci_dev->config_read = config_read;
+    pci_dev->config_write = config_write;
+    pci_dev->irq_index = pci_irq_index++;
+    bus->devices[devfn] = pci_dev;
+    pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, 4);
+    return pci_dev;
+}
+
+void pci_register_io_region(PCIDevice *pci_dev, int region_num,
+                            uint32_t size, int type,
+                            PCIMapIORegionFunc *map_func)
+{
+    PCIIORegion *r;
+    uint32_t addr;
+
+    if ((unsigned int)region_num >= PCI_NUM_REGIONS)
+        return;
+    r = &pci_dev->io_regions[region_num];
+    r->addr = -1;
+    r->size = size;
+    r->type = type;
+    r->map_func = map_func;
+    if (region_num == PCI_ROM_SLOT) {
+        addr = 0x30;
+    } else {
+        addr = 0x10 + region_num * 4;
+    }
+    *(uint32_t *)(pci_dev->config + addr) = cpu_to_le32(type);
+}
+
+target_phys_addr_t pci_to_cpu_addr(target_phys_addr_t addr)
+{
+    return addr + pci_mem_base;
+}
+
+static void pci_update_mappings(PCIDevice *d)
+{
+    PCIIORegion *r;
+    int cmd, i;
+    uint32_t last_addr, new_addr, config_ofs;
+
+    cmd = le16_to_cpu(*(uint16_t *)(d->config + PCI_COMMAND));
+    for(i = 0; i < PCI_NUM_REGIONS; i++) {
+        r = &d->io_regions[i];
+        if (i == PCI_ROM_SLOT) {
+            config_ofs = 0x30;
+        } else {
+            config_ofs = 0x10 + i * 4;
+        }
+        if (r->size != 0) {
+            if (r->type & PCI_ADDRESS_SPACE_IO) {
+                if (cmd & PCI_COMMAND_IO) {
+                    new_addr = le32_to_cpu(*(uint32_t *)(d->config +
+                                                         config_ofs));
+                    new_addr = new_addr & ~(r->size - 1);
+                    last_addr = new_addr + r->size - 1;
+                    /* NOTE: we have only 64K ioports on PC */
+                    if (last_addr <= new_addr || new_addr == 0 ||
+                        last_addr >= 0x10000) {
+                        new_addr = -1;
+                    }
+                } else {
+                    new_addr = -1;
+                }
+            } else {
+                if (cmd & PCI_COMMAND_MEMORY) {
+                    new_addr = le32_to_cpu(*(uint32_t *)(d->config +
+                                                         config_ofs));
+                    /* the ROM slot has a specific enable bit */
+                    if (i == PCI_ROM_SLOT && !(new_addr & 1))
+                        goto no_mem_map;
+                    new_addr = new_addr & ~(r->size - 1);
+                    last_addr = new_addr + r->size - 1;
+                    /* NOTE: we do not support wrapping */
+                    /* XXX: as we cannot support really dynamic
+                       mappings, we handle specific values as invalid
+                       mappings. */
+                    if (last_addr <= new_addr || new_addr == 0 ||
+                        last_addr == -1) {
+                        new_addr = -1;
+                    }
+                } else {
+                no_mem_map:
+                    new_addr = -1;
+                }
+            }
+            /* now do the real mapping */
+            if (new_addr != r->addr) {
+                if (r->addr != -1) {
+#ifndef IOEMU
+                    if (r->type & PCI_ADDRESS_SPACE_IO) {
+                        int class;
+                        /* NOTE: specific hack for IDE in PC case:
+                           only one byte must be mapped. */
+                        class = d->config[0x0a] | (d->config[0x0b] << 8);
+                        if (class == 0x0101 && r->size == 4) {
+                            isa_unassign_ioport(r->addr + 2, 1);
+                        } else {
+                            isa_unassign_ioport(r->addr, r->size);
+                        }
+                    } else {
+                        cpu_register_physical_memory(pci_to_cpu_addr(r->addr),
+                                                     r->size,
+                                                     IO_MEM_UNASSIGNED);
+                    }
+#endif
+                }
+                r->addr = new_addr;
+                if (r->addr != -1) {
+                    r->map_func(d, i, r->addr, r->size, r->type);
+                }
+            }
+        }
+    }
+}
+
+uint32_t pci_default_read_config(PCIDevice *d,
+                                 uint32_t address, int len)
+{
+    uint32_t val;
+
+    switch(len) {
+    default:
+    case 4:
+       if (address <= 0xfc) {
+           val = le32_to_cpu(*(uint32_t *)(d->config + address));
+           break;
+       }
+       /* fall through */
+    case 2:
+        if (address <= 0xfe) {
+           val = le16_to_cpu(*(uint16_t *)(d->config + address));
+           break;
+       }
+       /* fall through */
+    case 1:
+        val = d->config[address];
+        break;
+    }
+    return val;
+}
+
+void pci_default_write_config(PCIDevice *d,
+                              uint32_t address, uint32_t val, int len)
+{
+    int can_write, i;
+    uint32_t end, addr;
+
+    if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) ||
+                     (address >= 0x30 && address < 0x34))) {
+        PCIIORegion *r;
+        int reg;
+
+        if ( address >= 0x30 ) {
+            reg = PCI_ROM_SLOT;
+        }else{
+            reg = (address - 0x10) >> 2;
+        }
+        r = &d->io_regions[reg];
+        if (r->size == 0)
+            goto default_config;
+        /* compute the stored value */
+        if (reg == PCI_ROM_SLOT) {
+            /* keep ROM enable bit */
+            val &= (~(r->size - 1)) | 1;
+        } else {
+            val &= ~(r->size - 1);
+            val |= r->type;
+        }
+        *(uint32_t *)(d->config + address) = cpu_to_le32(val);
+        pci_update_mappings(d);
+        return;
+    }
+ default_config:
+    /* not efficient, but simple */
+    addr = address;
+    for(i = 0; i < len; i++) {
+        /* default read/write accesses */
+        switch(d->config[0x0e]) {
+        case 0x00:
+        case 0x80:
+            switch(addr) {
+            case 0x00:
+            case 0x01:
+            case 0x02:
+            case 0x03:
+            case 0x08:
+            case 0x09:
+            case 0x0a:
+            case 0x0b:
+            case 0x0e:
+            case 0x10 ... 0x27: /* base */
+            case 0x30 ... 0x33: /* rom */
+            case 0x3d:
+                can_write = 0;
+                break;
+            default:
+                can_write = 1;
+                break;
+            }
+            break;
+        default:
+        case 0x01:
+            switch(addr) {
+            case 0x00:
+            case 0x01:
+            case 0x02:
+            case 0x03:
+            case 0x08:
+            case 0x09:
+            case 0x0a:
+            case 0x0b:
+            case 0x0e:
+            case 0x38 ... 0x3b: /* rom */
+            case 0x3d:
+                can_write = 0;
+                break;
+            default:
+                can_write = 1;
+                break;
+            }
+            break;
+        }
+        if (can_write) {
+            d->config[addr] = val;
+        }
+        if (++addr > 0xff)
+               break;
+        val >>= 8;
+    }
+
+    end = address + len;
+    if (end > PCI_COMMAND && address < (PCI_COMMAND + 2)) {
+      pci_info ();
+        /* if the command register is modified, we must modify the mappings */
+        pci_update_mappings(d);
+    }
+}
+
+void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len)
+{
+    PCIBus *s = opaque;
+    PCIDevice *pci_dev;
+    int config_addr, bus_num;
+
+#if defined(DEBUG_PCI) && 0
+    printf("pci_data_write: addr=%08x val=%08x len=%d\n",
+           addr, val, len);
+#endif
+    bus_num = (addr >> 16) & 0xff;
+    while (s && s->bus_num != bus_num)
+        s = s->next;
+    if (!s)
+        return;
+    pci_dev = s->devices[(addr >> 8) & 0xff];
+    if (!pci_dev)
+        return;
+    config_addr = addr & 0xff;
+#if defined(DEBUG_PCI)
+    printf("pci_config_write: %s: addr=%02x val=%08x len=%d\n",
+           pci_dev->name, config_addr, val, len);
+#endif
+    pci_dev->config_write(pci_dev, config_addr, val, len);
+}
+
+uint32_t pci_data_read(void *opaque, uint32_t addr, int len)
+{
+    PCIBus *s = opaque;
+    PCIDevice *pci_dev;
+    int config_addr, bus_num;
+    uint32_t val;
+
+    bus_num = (addr >> 16) & 0xff;
+    while (s && s->bus_num != bus_num)
+        s= s->next;
+    if (!s)
+        goto fail;
+    pci_dev = s->devices[(addr >> 8) & 0xff];
+    if (!pci_dev) {
+    fail:
+        switch(len) {
+        case 1:
+            val = 0xff;
+            break;
+        case 2:
+            val = 0xffff;
+            break;
+        default:
+        case 4:
+            val = 0xffffffff;
+            break;
+        }
+        goto the_end;
+    }
+    config_addr = addr & 0xff;
+    val = pci_dev->config_read(pci_dev, config_addr, len);
+#if defined(DEBUG_PCI)
+    printf("pci_config_read: %s: addr=%02x val=%08x len=%d\n",
+           pci_dev->name, config_addr, val, len);
+#endif
+ the_end:
+#if defined(DEBUG_PCI) && 0
+    printf("pci_data_read: addr=%08x val=%08x len=%d\n",
+           addr, val, len);
+#endif
+    return val;
+}
+
+/***********************************************************/
+/* generic PCI irq support */
+
+/* 0 <= irq_num <= 3. level must be 0 or 1 */
+static void pci_set_irq(void *opaque, int irq_num, int level)
+{
+    PCIDevice *pci_dev = (PCIDevice *)opaque;
+    PCIBus *bus;
+    int change;
+
+    change = level - pci_dev->irq_state[irq_num];
+    if (!change)
+        return;
+
+    pci_dev->irq_state[irq_num] = level;
+    for (;;) {
+        bus = pci_dev->bus;
+        irq_num = bus->map_irq(pci_dev, irq_num);
+        if (bus->set_irq)
+            break;
+        pci_dev = bus->parent_dev;
+    }
+    bus->irq_count[irq_num] += change;
+    bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0);
+}
+
+/***********************************************************/
+/* monitor info on PCI */
+
+typedef struct {
+    uint16_t class;
+    const char *desc;
+} pci_class_desc;
+
+static pci_class_desc pci_class_descriptions[] =
+{
+    { 0x0100, "SCSI controller"},
+    { 0x0101, "IDE controller"},
+    { 0x0102, "Floppy controller"},
+    { 0x0103, "IPI controller"},
+    { 0x0104, "RAID controller"},
+    { 0x0106, "SATA controller"},
+    { 0x0107, "SAS controller"},
+    { 0x0180, "Storage controller"},
+    { 0x0200, "Ethernet controller"},
+    { 0x0201, "Token Ring controller"},
+    { 0x0202, "FDDI controller"},
+    { 0x0203, "ATM controller"},
+    { 0x0280, "Network controller"},
+    { 0x0300, "VGA controller"},
+    { 0x0301, "XGA controller"},
+    { 0x0302, "3D controller"},
+    { 0x0380, "Display controller"},
+    { 0x0400, "Video controller"},
+    { 0x0401, "Audio controller"},
+    { 0x0402, "Phone"},
+    { 0x0480, "Multimedia controller"},
+    { 0x0500, "RAM controller"},
+    { 0x0501, "Flash controller"},
+    { 0x0580, "Memory controller"},
+    { 0x0600, "Host bridge"},
+    { 0x0601, "ISA bridge"},
+    { 0x0602, "EISA bridge"},
+    { 0x0603, "MC bridge"},
+    { 0x0604, "PCI bridge"},
+    { 0x0605, "PCMCIA bridge"},
+    { 0x0606, "NUBUS bridge"},
+    { 0x0607, "CARDBUS bridge"},
+    { 0x0608, "RACEWAY bridge"},
+    { 0x0680, "Bridge"},
+    { 0x0c03, "USB controller"},
+    { 0, NULL}
+};
+
+static void pci_info_device(PCIDevice *d)
+{
+    int i, class;
+    PCIIORegion *r;
+    pci_class_desc *desc;
+
+    term_printf("  Bus %2d, device %3d, function %d:\n",
+           d->bus->bus_num, d->devfn >> 3, d->devfn & 7);
+    class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE)));
+    term_printf("    ");
+    desc = pci_class_descriptions;
+    while (desc->desc && class != desc->class)
+        desc++;
+    if (desc->desc) {
+        term_printf("%s", desc->desc);
+    } else {
+        term_printf("Class %04x", class);
+    }
+    term_printf(": PCI device %04x:%04x\n",
+           le16_to_cpu(*((uint16_t *)(d->config + PCI_VENDOR_ID))),
+           le16_to_cpu(*((uint16_t *)(d->config + PCI_DEVICE_ID))));
+
+    if (d->config[PCI_INTERRUPT_PIN] != 0) {
+        term_printf("      IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]);
+    }
+    if (class == 0x0604) {
+        term_printf("      BUS %d.\n", d->config[0x19]);
+    }
+    for(i = 0;i < PCI_NUM_REGIONS; i++) {
+        r = &d->io_regions[i];
+        if (r->size != 0) {
+            term_printf("      BAR%d: ", i);
+            if (r->type & PCI_ADDRESS_SPACE_IO) {
+                term_printf("I/O at 0x%04x [0x%04x].\n",
+                       r->addr, r->addr + r->size - 1);
+            } else {
+                term_printf("32 bit memory at 0x%08x [0x%08x].\n",
+                       r->addr, r->addr + r->size - 1);
+            }
+        }
+    }
+    if (class == 0x0604 && d->config[0x19] != 0) {
+        pci_for_each_device(d->config[0x19], pci_info_device);
+    }
+}
+
+void pci_for_each_device(int bus_num, void (*fn)(PCIDevice *d))
+{
+    PCIBus *bus = first_bus;
+    PCIDevice *d;
+    int devfn;
+
+    while (bus && bus->bus_num != bus_num)
+        bus = bus->next;
+    if (bus) {
+        for(devfn = 0; devfn < 256; devfn++) {
+            d = bus->devices[devfn];
+            if (d)
+                fn(d);
+        }
+    }
+}
+
+void pci_info(void)
+{
+    pci_for_each_device(0, pci_info_device);
+}
+
+#ifndef IOEMU
+/* Initialize a PCI NIC.  */
+void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn)
+{
+    if (strcmp(nd->model, "ne2k_pci") == 0) {
+        pci_ne2000_init(bus, nd, devfn);
+    } else if (strcmp(nd->model, "i82551") == 0) {
+        pci_i82551_init(bus, nd, devfn);
+    } else if (strcmp(nd->model, "i82557b") == 0) {
+        pci_i82557b_init(bus, nd, devfn);
+    } else if (strcmp(nd->model, "i82559er") == 0) {
+        pci_i82559er_init(bus, nd, devfn);
+    } else if (strcmp(nd->model, "rtl8139") == 0) {
+        pci_rtl8139_init(bus, nd, devfn);
+    } else if (strcmp(nd->model, "pcnet") == 0) {
+        pci_pcnet_init(bus, nd, devfn);
+    } else if (strcmp(nd->model, "?") == 0) {
+        fprintf(stderr, "qemu: Supported PCI NICs: i82551 i82557b i82559er"
+                        " ne2k_pci pcnet rtl8139\n");
+        exit (1);
+    } else {
+        fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
+        exit (1);
+    }
+}
+
+typedef struct {
+    PCIDevice dev;
+    PCIBus *bus;
+} PCIBridge;
+
+void pci_bridge_write_config(PCIDevice *d,
+                             uint32_t address, uint32_t val, int len)
+{
+    PCIBridge *s = (PCIBridge *)d;
+
+    if (address == 0x19 || (address == 0x18 && len > 1)) {
+        if (address == 0x19)
+            s->bus->bus_num = val & 0xff;
+        else
+            s->bus->bus_num = (val >> 8) & 0xff;
+#if defined(DEBUG_PCI)
+        printf ("pci-bridge: %s: Assigned bus %d\n", d->name, s->bus->bus_num);
+#endif
+    }
+    pci_default_write_config(d, address, val, len);
+}
+
+PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id,
+                        pci_map_irq_fn map_irq, const char *name)
+{
+    PCIBridge *s;
+    s = (PCIBridge *)pci_register_device(bus, name, sizeof(PCIBridge),
+                                         devfn, NULL, pci_bridge_write_config);
+    s->dev.config[0x00] = id >> 16;
+    s->dev.config[0x01] = id >> 24;
+    s->dev.config[0x02] = id; // device_id
+    s->dev.config[0x03] = id >> 8;
+    s->dev.config[0x04] = 0x06; // command = bus master, pci mem
+    s->dev.config[0x05] = 0x00;
+    s->dev.config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
+    s->dev.config[0x07] = 0x00; // status = fast devsel
+    s->dev.config[0x08] = 0x00; // revision
+    s->dev.config[0x09] = 0x00; // programming i/f
+    s->dev.config[0x0A] = 0x04; // class_sub = PCI to PCI bridge
+    s->dev.config[0x0B] = 0x06; // class_base = PCI_bridge
+    s->dev.config[0x0D] = 0x10; // latency_timer
+    s->dev.config[0x0E] = 0x81; // header_type
+    s->dev.config[0x1E] = 0xa0; // secondary status
+
+    s->bus = pci_register_secondary_bus(&s->dev, map_irq);
+    return s->bus;
+}
+#endif
diff -r 092232fa1fbd extras/stubfw/ioemu/pci_host.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/ioemu/pci_host.h    Mon Nov 12 02:26:13 2007 +0100
@@ -0,0 +1,93 @@
+/*
+ * QEMU Common PCI Host bridge configuration data space access routines.
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* Worker routines for a PCI host controller that uses an {address,data}
+   register pair to access PCI configuration space.  */
+
+typedef struct {
+    uint32_t config_reg;
+    PCIBus *bus;
+} PCIHostState;
+
+static void pci_host_data_writeb(void* opaque, pci_addr_t addr, uint32_t val)
+{
+    PCIHostState *s = opaque;
+    if (s->config_reg & (1u << 31))
+        pci_data_write(s->bus, s->config_reg | (addr & 3), val, 1);
+}
+
+static void pci_host_data_writew(void* opaque, pci_addr_t addr, uint32_t val)
+{
+    PCIHostState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = bswap16(val);
+#endif
+    if (s->config_reg & (1u << 31))
+        pci_data_write(s->bus, s->config_reg | (addr & 3), val, 2);
+}
+
+static void pci_host_data_writel(void* opaque, pci_addr_t addr, uint32_t val)
+{
+    PCIHostState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = bswap32(val);
+#endif
+    if (s->config_reg & (1u << 31))
+        pci_data_write(s->bus, s->config_reg, val, 4);
+}
+
+static uint32_t pci_host_data_readb(void* opaque, pci_addr_t addr)
+{
+    PCIHostState *s = opaque;
+    if (!(s->config_reg & (1 << 31)))
+        return 0xff;
+    return pci_data_read(s->bus, s->config_reg | (addr & 3), 1);
+}
+
+static uint32_t pci_host_data_readw(void* opaque, pci_addr_t addr)
+{
+    PCIHostState *s = opaque;
+    uint32_t val;
+    if (!(s->config_reg & (1 << 31)))
+        return 0xffff;
+    val = pci_data_read(s->bus, s->config_reg | (addr & 3), 2);
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = bswap16(val);
+#endif
+    return val;
+}
+
+static uint32_t pci_host_data_readl(void* opaque, pci_addr_t addr)
+{
+    PCIHostState *s = opaque;
+    uint32_t val;
+    if (!(s->config_reg & (1 << 31)))
+        return 0xffffffff;
+    val = pci_data_read(s->bus, s->config_reg | (addr & 3), 4);
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = bswap32(val);
+#endif
+    return val;
+}
+
diff -r 092232fa1fbd extras/stubfw/ioemu/piix_pci.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/ioemu/piix_pci.c    Mon Nov 12 04:00:41 2007 +0100
@@ -0,0 +1,396 @@
+/*
+ * QEMU i440FX/PIIX3 PCI Bridge Emulation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vl.h"
+typedef uint32_t pci_addr_t;
+#include "pci_host.h"
+
+typedef PCIHostState I440FXState;
+
+static void i440fx_addr_writel(void* opaque, uint32_t addr, uint32_t val)
+{
+    I440FXState *s = opaque;
+    s->config_reg = val;
+}
+
+static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr)
+{
+    I440FXState *s = opaque;
+    return s->config_reg;
+}
+
+static void piix3_set_irq(qemu_irq *pic, int irq_num, int level);
+
+/* return the global irq number corresponding to a given device irq
+   pin. We could also use the bus number to have a more precise
+   mapping. */
+static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
+{
+    int slot_addend;
+    slot_addend = (pci_dev->devfn >> 3) - 1;
+    return (irq_num + slot_addend) & 3;
+}
+
+#ifndef IOEMU
+
+static uint32_t isa_page_descs[384 / 4];
+static uint8_t smm_enabled;
+
+static void update_pam(PCIDevice *d, uint32_t start, uint32_t end, int r)
+{
+    uint32_t addr;
+
+    //    printf("ISA mapping %08x-0x%08x: %d\n", start, end, r);
+    switch(r) {
+    case 3:
+        /* RAM */
+        cpu_register_physical_memory(start, end - start,
+                                     start);
+        break;
+    case 1:
+        /* ROM (XXX: not quite correct) */
+        cpu_register_physical_memory(start, end - start,
+                                     start | IO_MEM_ROM);
+        break;
+    case 2:
+    case 0:
+        /* XXX: should distinguish read/write cases */
+        for(addr = start; addr < end; addr += 4096) {
+            cpu_register_physical_memory(addr, 4096,
+                                         isa_page_descs[(addr - 0xa0000) >> 
12]);
+        }
+        break;
+    }
+}
+
+static void i440fx_update_memory_mappings(PCIDevice *d)
+{
+    int i, r;
+    uint32_t smram, addr;
+
+    update_pam(d, 0xf0000, 0x100000, (d->config[0x59] >> 4) & 3);
+    for(i = 0; i < 12; i++) {
+        r = (d->config[(i >> 1) + 0x5a] >> ((i & 1) * 4)) & 3;
+        update_pam(d, 0xc0000 + 0x4000 * i, 0xc0000 + 0x4000 * (i + 1), r);
+    }
+    smram = d->config[0x72];
+    if ((smm_enabled && (smram & 0x08)) || (smram & 0x40)) {
+        cpu_register_physical_memory(0xa0000, 0x20000, 0xa0000);
+    } else {
+        for(addr = 0xa0000; addr < 0xc0000; addr += 4096) {
+            cpu_register_physical_memory(addr, 4096,
+                                         isa_page_descs[(addr - 0xa0000) >> 
12]);
+        }
+    }
+}
+
+void i440fx_set_smm(PCIDevice *d, int val)
+{
+    val = (val != 0);
+    if (smm_enabled != val) {
+        smm_enabled = val;
+        i440fx_update_memory_mappings(d);
+    }
+}
+
+
+/* XXX: suppress when better memory API. We make the assumption that
+   no device (in particular the VGA) changes the memory mappings in
+   the 0xa0000-0x100000 range */
+void i440fx_init_memory_mappings(PCIDevice *d)
+{
+    int i;
+    for(i = 0; i < 96; i++) {
+        isa_page_descs[i] = cpu_get_physical_page_desc(0xa0000 + i * 0x1000);
+    }
+}
+#endif
+
+static void i440fx_write_config(PCIDevice *d,
+                                uint32_t address, uint32_t val, int len)
+{
+    /* XXX: implement SMRAM.D_LOCK */
+    pci_default_write_config(d, address, val, len);
+#ifndef IOEMU
+    if ((address >= 0x59 && address <= 0x5f) || address == 0x72)
+        i440fx_update_memory_mappings(d);
+#endif
+}
+
+#ifndef IOEMU
+static void i440fx_save(QEMUFile* f, void *opaque)
+{
+    PCIDevice *d = opaque;
+    pci_device_save(d, f);
+    qemu_put_8s(f, &smm_enabled);
+}
+
+static int i440fx_load(QEMUFile* f, void *opaque, int version_id)
+{
+    PCIDevice *d = opaque;
+    int ret;
+
+    if (version_id != 1)
+        return -EINVAL;
+    ret = pci_device_load(d, f);
+    if (ret < 0)
+        return ret;
+    i440fx_update_memory_mappings(d);
+    qemu_get_8s(f, &smm_enabled);
+    return 0;
+}
+#endif
+
+PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic)
+{
+    PCIBus *b;
+    PCIDevice *d;
+    I440FXState *s;
+
+    s = qemu_mallocz(sizeof(I440FXState));
+    b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, pic, 0, 4);
+    s->bus = b;
+
+    register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s);
+    register_ioport_read(0xcf8, 4, 4, i440fx_addr_readl, s);
+
+    register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s);
+    register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s);
+    register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s);
+    register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s);
+    register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s);
+    register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s);
+
+    pci_info ();
+    printf ("Register i440FX\n");
+    d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0,
+                            NULL, i440fx_write_config);
+
+    d->config[0x00] = 0x86; // vendor_id
+    d->config[0x01] = 0x80;
+    d->config[0x02] = 0x37; // device_id
+    d->config[0x03] = 0x12;
+    d->config[0x08] = 0x02; // revision
+    d->config[0x0a] = 0x00; // class_sub = host2pci
+    d->config[0x0b] = 0x06; // class_base = PCI_bridge
+    d->config[0x0e] = 0x00; // header_type
+
+    d->config[0x72] = 0x02; /* SMRAM */
+
+    register_savevm("I440FX", 0, 1, i440fx_save, i440fx_load, d);
+    *pi440fx_state = d;
+    return b;
+}
+
+/* PIIX3 PCI to ISA bridge */
+
+PCIDevice *piix3_dev;
+PCIDevice *piix4_dev;
+
+/* just used for simpler irq handling. */
+#define PCI_IRQ_WORDS   ((PCI_DEVICES_MAX + 31) / 32)
+
+static int pci_irq_levels[4];
+
+static void piix3_set_irq(qemu_irq *pic, int irq_num, int level)
+{
+    int i, pic_irq, pic_level;
+
+    piix3_dev->config[0x60 + irq_num] &= ~0x80;   // enable bit
+    pci_irq_levels[irq_num] = level;
+
+    /* now we change the pic irq level according to the piix irq mappings */
+    /* XXX: optimize */
+    pic_irq = piix3_dev->config[0x60 + irq_num];
+    if (pic_irq < 16) {
+        /* The pic level is the logical OR of all the PCI irqs mapped
+           to it */
+        pic_level = 0;
+        for (i = 0; i < 4; i++) {
+            if (pic_irq == piix3_dev->config[0x60 + i])
+                pic_level |= pci_irq_levels[i];
+        }
+        qemu_set_irq(pic[pic_irq], pic_level);
+    }
+}
+
+static void piix3_reset(PCIDevice *d)
+{
+    uint8_t *pci_conf = d->config;
+
+    pci_conf[0x04] = 0x07; // master, memory and I/O
+    pci_conf[0x05] = 0x00;
+    pci_conf[0x06] = 0x00;
+    pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
+    pci_conf[0x4c] = 0x4d;
+    pci_conf[0x4e] = 0x03;
+    pci_conf[0x4f] = 0x00;
+    pci_conf[0x60] = 0x80;
+    pci_conf[0x69] = 0x02;
+    pci_conf[0x70] = 0x80;
+    pci_conf[0x76] = 0x0c;
+    pci_conf[0x77] = 0x0c;
+    pci_conf[0x78] = 0x02;
+    pci_conf[0x79] = 0x00;
+    pci_conf[0x80] = 0x00;
+    pci_conf[0x82] = 0x00;
+    pci_conf[0xa0] = 0x08;
+    pci_conf[0xa2] = 0x00;
+    pci_conf[0xa3] = 0x00;
+    pci_conf[0xa4] = 0x00;
+    pci_conf[0xa5] = 0x00;
+    pci_conf[0xa6] = 0x00;
+    pci_conf[0xa7] = 0x00;
+    pci_conf[0xa8] = 0x0f;
+    pci_conf[0xaa] = 0x00;
+    pci_conf[0xab] = 0x00;
+    pci_conf[0xac] = 0x00;
+    pci_conf[0xae] = 0x00;
+}
+
+static void piix4_reset(PCIDevice *d)
+{
+    uint8_t *pci_conf = d->config;
+
+    pci_conf[0x04] = 0x07; // master, memory and I/O
+    pci_conf[0x05] = 0x00;
+    pci_conf[0x06] = 0x00;
+    pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
+    pci_conf[0x4c] = 0x4d;
+    pci_conf[0x4e] = 0x03;
+    pci_conf[0x4f] = 0x00;
+    pci_conf[0x60] = 0x0a; // PCI A -> IRQ 10
+    pci_conf[0x61] = 0x0a; // PCI B -> IRQ 10
+    pci_conf[0x62] = 0x0b; // PCI C -> IRQ 11
+    pci_conf[0x63] = 0x0b; // PCI D -> IRQ 11
+    pci_conf[0x69] = 0x02;
+    pci_conf[0x70] = 0x80;
+    pci_conf[0x76] = 0x0c;
+    pci_conf[0x77] = 0x0c;
+    pci_conf[0x78] = 0x02;
+    pci_conf[0x79] = 0x00;
+    pci_conf[0x80] = 0x00;
+    pci_conf[0x82] = 0x00;
+    pci_conf[0xa0] = 0x08;
+    pci_conf[0xa2] = 0x00;
+    pci_conf[0xa3] = 0x00;
+    pci_conf[0xa4] = 0x00;
+    pci_conf[0xa5] = 0x00;
+    pci_conf[0xa6] = 0x00;
+    pci_conf[0xa7] = 0x00;
+    pci_conf[0xa8] = 0x0f;
+    pci_conf[0xaa] = 0x00;
+    pci_conf[0xab] = 0x00;
+    pci_conf[0xac] = 0x00;
+    pci_conf[0xae] = 0x00;
+}
+
+#ifndef IOEMU
+static void piix_save(QEMUFile* f, void *opaque)
+{
+    PCIDevice *d = opaque;
+    pci_device_save(d, f);
+}
+
+static int piix_load(QEMUFile* f, void *opaque, int version_id)
+{
+    PCIDevice *d = opaque;
+    if (version_id != 2)
+        return -EINVAL;
+    return pci_device_load(d, f);
+}
+#endif
+
+int piix_init(PCIBus *bus, int devfn)
+{
+    PCIDevice *d;
+    uint8_t *pci_conf;
+
+    d = pci_register_device(bus, "PIIX", sizeof(PCIDevice),
+                                    devfn, NULL, NULL);
+    register_savevm("PIIX", 0, 2, piix_save, piix_load, d);
+
+    piix3_dev = d;
+    pci_conf = d->config;
+
+    pci_conf[0x00] = 0x86; // Intel
+    pci_conf[0x01] = 0x80;
+    pci_conf[0x02] = 0x2E; // 82371FB PIIX PCI-to-ISA bridge
+    pci_conf[0x03] = 0x12;
+    pci_conf[0x08] = 0x02; // Step A1
+    pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
+    pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
+    pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
+
+    piix3_reset(d);
+    return d->devfn;
+}
+
+int piix3_init(PCIBus *bus, int devfn)
+{
+    PCIDevice *d;
+    uint8_t *pci_conf;
+
+    d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice),
+                                    devfn, NULL, NULL);
+    register_savevm("PIIX3", 0, 2, piix_save, piix_load, d);
+
+    piix3_dev = d;
+    pci_conf = d->config;
+
+    pci_conf[0x00] = 0x86; // Intel
+    pci_conf[0x01] = 0x80;
+    pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
+    pci_conf[0x03] = 0x70;
+    pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
+    pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
+    pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
+
+    piix3_reset(d);
+    return d->devfn;
+}
+
+int piix4_init(PCIBus *bus, int devfn)
+{
+    PCIDevice *d;
+    uint8_t *pci_conf;
+
+    d = pci_register_device(bus, "PIIX4", sizeof(PCIDevice),
+                                    devfn, NULL, NULL);
+    register_savevm("PIIX4", 0, 2, piix_save, piix_load, d);
+
+    piix4_dev = d;
+    pci_conf = d->config;
+
+    pci_conf[0x00] = 0x86; // Intel
+    pci_conf[0x01] = 0x80;
+    pci_conf[0x02] = 0x10; // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge
+    pci_conf[0x03] = 0x71;
+    pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
+    pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
+    pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
+
+    piix4_reset(d);
+    return d->devfn;
+}
diff -r 092232fa1fbd extras/stubfw/ioemu/readline.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/ioemu/readline.c    Sun Nov 18 07:50:13 2007 +0100
@@ -0,0 +1,487 @@
+/*
+ * QEMU readline utility
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+#define TERM_CMD_BUF_SIZE 4095
+#define TERM_MAX_CMDS 64
+#define NB_COMPLETIONS_MAX 256
+
+#define IS_NORM 0
+#define IS_ESC  1
+#define IS_CSI  2
+
+#define printf do_not_use_printf
+
+static char term_cmd_buf[TERM_CMD_BUF_SIZE + 1];
+static int term_cmd_buf_index;
+static int term_cmd_buf_size;
+
+static char term_last_cmd_buf[TERM_CMD_BUF_SIZE + 1];
+static int term_last_cmd_buf_index;
+static int term_last_cmd_buf_size;
+
+static int term_esc_state;
+static int term_esc_param;
+
+static char *term_history[TERM_MAX_CMDS];
+static int term_hist_entry = -1;
+
+static int nb_completions;
+int completion_index;
+static char *completions[NB_COMPLETIONS_MAX];
+
+static ReadLineFunc *term_readline_func;
+static int term_is_password;
+static char term_prompt[256];
+static void *term_readline_opaque;
+
+static void term_show_prompt2(void)
+{
+    term_printf("%s", term_prompt);
+    term_flush();
+    term_last_cmd_buf_index = 0;
+    term_last_cmd_buf_size = 0;
+    term_esc_state = IS_NORM;
+}
+
+static void term_show_prompt(void)
+{
+    term_show_prompt2();
+    term_cmd_buf_index = 0;
+    term_cmd_buf_size = 0;
+}
+
+/* update the displayed command line */
+static void term_update(void)
+{
+    int i, delta, len;
+
+    if (term_cmd_buf_size != term_last_cmd_buf_size ||
+        memcmp(term_cmd_buf, term_last_cmd_buf, term_cmd_buf_size) != 0) {
+        for(i = 0; i < term_last_cmd_buf_index; i++) {
+            term_printf("\033[D");
+        }
+        term_cmd_buf[term_cmd_buf_size] = '\0';
+        if (term_is_password) {
+            len = strlen(term_cmd_buf);
+            for(i = 0; i < len; i++)
+                term_printf("*");
+        } else {
+            term_printf("%s", term_cmd_buf);
+        }
+        term_printf("\033[K");
+        memcpy(term_last_cmd_buf, term_cmd_buf, term_cmd_buf_size);
+        term_last_cmd_buf_size = term_cmd_buf_size;
+        term_last_cmd_buf_index = term_cmd_buf_size;
+    }
+    if (term_cmd_buf_index != term_last_cmd_buf_index) {
+        delta = term_cmd_buf_index - term_last_cmd_buf_index;
+        if (delta > 0) {
+            for(i = 0;i < delta; i++) {
+                term_printf("\033[C");
+            }
+        } else {
+            delta = -delta;
+            for(i = 0;i < delta; i++) {
+                term_printf("\033[D");
+            }
+        }
+        term_last_cmd_buf_index = term_cmd_buf_index;
+    }
+    term_flush();
+}
+
+static void term_insert_char(int ch)
+{
+    if (term_cmd_buf_index < TERM_CMD_BUF_SIZE) {
+        memmove(term_cmd_buf + term_cmd_buf_index + 1,
+                term_cmd_buf + term_cmd_buf_index,
+                term_cmd_buf_size - term_cmd_buf_index);
+        term_cmd_buf[term_cmd_buf_index] = ch;
+        term_cmd_buf_size++;
+        term_cmd_buf_index++;
+    }
+}
+
+static void term_backward_char(void)
+{
+    if (term_cmd_buf_index > 0) {
+        term_cmd_buf_index--;
+    }
+}
+
+static void term_forward_char(void)
+{
+    if (term_cmd_buf_index < term_cmd_buf_size) {
+        term_cmd_buf_index++;
+    }
+}
+
+static void term_delete_char(void)
+{
+    if (term_cmd_buf_index < term_cmd_buf_size) {
+        memmove(term_cmd_buf + term_cmd_buf_index,
+                term_cmd_buf + term_cmd_buf_index + 1,
+                term_cmd_buf_size - term_cmd_buf_index - 1);
+        term_cmd_buf_size--;
+    }
+}
+
+static void term_backspace(void)
+{
+    if (term_cmd_buf_index > 0) {
+        term_backward_char();
+        term_delete_char();
+    }
+}
+
+static void term_backword(void)
+{
+    int start;
+
+    if (term_cmd_buf_index == 0 || term_cmd_buf_index > term_cmd_buf_size) {
+        return;
+    }
+
+    start = term_cmd_buf_index - 1;
+
+    /* find first word (backwards) */
+    while (start > 0) {
+        if (!isspace(term_cmd_buf[start])) {
+            break;
+        }
+
+        --start;
+    }
+
+    /* find first space (backwards) */
+    while (start > 0) {
+        if (isspace(term_cmd_buf[start])) {
+            ++start;
+            break;
+        }
+
+        --start;
+    }
+
+    /* remove word */
+    if (start < term_cmd_buf_index) {
+        memmove(term_cmd_buf + start,
+                term_cmd_buf + term_cmd_buf_index,
+                term_cmd_buf_size - term_cmd_buf_index);
+        term_cmd_buf_size -= term_cmd_buf_index - start;
+        term_cmd_buf_index = start;
+    }
+}
+
+static void term_bol(void)
+{
+    term_cmd_buf_index = 0;
+}
+
+static void term_eol(void)
+{
+    term_cmd_buf_index = term_cmd_buf_size;
+}
+
+static void term_up_char(void)
+{
+    int idx;
+
+    if (term_hist_entry == 0)
+       return;
+    if (term_hist_entry == -1) {
+       /* Find latest entry */
+       for (idx = 0; idx < TERM_MAX_CMDS; idx++) {
+           if (term_history[idx] == NULL)
+               break;
+       }
+       term_hist_entry = idx;
+    }
+    term_hist_entry--;
+    if (term_hist_entry >= 0) {
+       pstrcpy(term_cmd_buf, sizeof(term_cmd_buf),
+                term_history[term_hist_entry]);
+       term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf);
+    }
+}
+
+static void term_down_char(void)
+{
+    if (term_hist_entry == TERM_MAX_CMDS - 1 || term_hist_entry == -1)
+       return;
+    if (term_history[++term_hist_entry] != NULL) {
+       pstrcpy(term_cmd_buf, sizeof(term_cmd_buf),
+                term_history[term_hist_entry]);
+    } else {
+       term_hist_entry = -1;
+    }
+    term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf);
+}
+
+static void term_hist_add(const char *cmdline)
+{
+    char *hist_entry, *new_entry;
+    int idx;
+
+    if (cmdline[0] == '\0')
+       return;
+    new_entry = NULL;
+    if (term_hist_entry != -1) {
+       /* We were editing an existing history entry: replace it */
+       hist_entry = term_history[term_hist_entry];
+       idx = term_hist_entry;
+       if (strcmp(hist_entry, cmdline) == 0) {
+           goto same_entry;
+       }
+    }
+    /* Search cmdline in history buffers */
+    for (idx = 0; idx < TERM_MAX_CMDS; idx++) {
+       hist_entry = term_history[idx];
+       if (hist_entry == NULL)
+           break;
+       if (strcmp(hist_entry, cmdline) == 0) {
+       same_entry:
+           new_entry = hist_entry;
+           /* Put this entry at the end of history */
+           memmove(&term_history[idx], &term_history[idx + 1],
+                   &term_history[TERM_MAX_CMDS] - &term_history[idx + 1]);
+           term_history[TERM_MAX_CMDS - 1] = NULL;
+           for (; idx < TERM_MAX_CMDS; idx++) {
+               if (term_history[idx] == NULL)
+                   break;
+           }
+           break;
+       }
+    }
+    if (idx == TERM_MAX_CMDS) {
+       /* Need to get one free slot */
+       free(term_history[0]);
+       memcpy(term_history, &term_history[1],
+              &term_history[TERM_MAX_CMDS] - &term_history[1]);
+       term_history[TERM_MAX_CMDS - 1] = NULL;
+       idx = TERM_MAX_CMDS - 1;
+    }
+    if (new_entry == NULL)
+       new_entry = strdup(cmdline);
+    term_history[idx] = new_entry;
+    term_hist_entry = -1;
+}
+
+/* completion support */
+
+void add_completion(const char *str)
+{
+    if (nb_completions < NB_COMPLETIONS_MAX) {
+        completions[nb_completions++] = qemu_strdup(str);
+    }
+}
+
+static void term_completion(void)
+{
+    int len, i, j, max_width, nb_cols, max_prefix;
+    char *cmdline;
+
+    nb_completions = 0;
+
+    cmdline = qemu_malloc(term_cmd_buf_index + 1);
+    if (!cmdline)
+        return;
+    memcpy(cmdline, term_cmd_buf, term_cmd_buf_index);
+    cmdline[term_cmd_buf_index] = '\0';
+    readline_find_completion(cmdline);
+    qemu_free(cmdline);
+
+    /* no completion found */
+    if (nb_completions <= 0)
+        return;
+    if (nb_completions == 1) {
+        len = strlen(completions[0]);
+        for(i = completion_index; i < len; i++) {
+            term_insert_char(completions[0][i]);
+        }
+        /* extra space for next argument. XXX: make it more generic */
+        if (len > 0 && completions[0][len - 1] != '/')
+            term_insert_char(' ');
+    } else {
+        term_printf("\n");
+        max_width = 0;
+        max_prefix = 0;        
+        for(i = 0; i < nb_completions; i++) {
+            len = strlen(completions[i]);
+            if (i==0) {
+                max_prefix = len;
+            } else {
+                if (len < max_prefix)
+                    max_prefix = len;
+                for(j=0; j<max_prefix; j++) {
+                    if (completions[i][j] != completions[0][j])
+                        max_prefix = j;
+                }
+            }
+            if (len > max_width)
+                max_width = len;
+        }
+        if (max_prefix > 0) 
+            for(i = completion_index; i < max_prefix; i++) {
+                term_insert_char(completions[0][i]);
+            }
+        max_width += 2;
+        if (max_width < 10)
+            max_width = 10;
+        else if (max_width > 80)
+            max_width = 80;
+        nb_cols = 80 / max_width;
+        j = 0;
+        for(i = 0; i < nb_completions; i++) {
+            term_printf("%-*s", max_width, completions[i]);
+            if (++j == nb_cols || i == (nb_completions - 1)) {
+                term_printf("\n");
+                j = 0;
+            }
+        }
+        term_show_prompt2();
+    }
+}
+
+/* return true if command handled */
+void readline_handle_byte(int ch)
+{
+    switch(term_esc_state) {
+    case IS_NORM:
+        switch(ch) {
+        case 1:
+            term_bol();
+            break;
+        case 4:
+            term_delete_char();
+            break;
+        case 5:
+            term_eol();
+            break;
+        case 9:
+            term_completion();
+            break;
+        case 10:
+        case 13:
+            term_cmd_buf[term_cmd_buf_size] = '\0';
+            if (!term_is_password)
+                term_hist_add(term_cmd_buf);
+            term_printf("\n");
+            term_cmd_buf_index = 0;
+            term_cmd_buf_size = 0;
+            term_last_cmd_buf_index = 0;
+            term_last_cmd_buf_size = 0;
+            /* NOTE: readline_start can be called here */
+            term_readline_func(term_readline_opaque, term_cmd_buf);
+            break;
+        case 23:
+            /* ^W */
+            term_backword();
+            break;
+        case 27:
+            term_esc_state = IS_ESC;
+            break;
+        case 127:
+        case 8:
+            term_backspace();
+            break;
+       case 155:
+            term_esc_state = IS_CSI;
+           break;
+        default:
+            if (ch >= 32) {
+                term_insert_char(ch);
+            }
+            break;
+        }
+        break;
+    case IS_ESC:
+        if (ch == '[') {
+            term_esc_state = IS_CSI;
+            term_esc_param = 0;
+        } else {
+            term_esc_state = IS_NORM;
+        }
+        break;
+    case IS_CSI:
+        switch(ch) {
+       case 'A':
+       case 'F':
+           term_up_char();
+           break;
+       case 'B':
+       case 'E':
+           term_down_char();
+           break;
+        case 'D':
+            term_backward_char();
+            break;
+        case 'C':
+            term_forward_char();
+            break;
+        case '0' ... '9':
+            term_esc_param = term_esc_param * 10 + (ch - '0');
+            goto the_end;
+        case '~':
+            switch(term_esc_param) {
+            case 1:
+                term_bol();
+                break;
+            case 3:
+                term_delete_char();
+                break;
+            case 4:
+                term_eol();
+                break;
+            }
+            break;
+        default:
+            break;
+        }
+        term_esc_state = IS_NORM;
+    the_end:
+        break;
+    }
+    term_update();
+}
+
+void readline_start(const char *prompt, int is_password,
+                    ReadLineFunc *readline_func, void *opaque)
+{
+    pstrcpy(term_prompt, sizeof(term_prompt), prompt);
+    term_readline_func = readline_func;
+    term_readline_opaque = opaque;
+    term_is_password = is_password;
+    term_show_prompt();
+}
+
+const char *readline_get_history(unsigned int index)
+{
+    if (index >= TERM_MAX_CMDS)
+        return NULL;
+    return term_history[index];
+}
+
+
diff -r 092232fa1fbd extras/stubfw/ioemu/serial.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/ioemu/serial.c      Sun Nov 18 06:42:11 2007 +0100
@@ -0,0 +1,478 @@
+/*
+ * QEMU 16450 UART emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+//#define DEBUG_SERIAL
+
+#define UART_LCR_DLAB  0x80    /* Divisor latch access bit */
+
+#define UART_IER_MSI   0x08    /* Enable Modem status interrupt */
+#define UART_IER_RLSI  0x04    /* Enable receiver line status interrupt */
+#define UART_IER_THRI  0x02    /* Enable Transmitter holding register int. */
+#define UART_IER_RDI   0x01    /* Enable receiver data interrupt */
+
+#define UART_IIR_NO_INT        0x01    /* No interrupts pending */
+#define UART_IIR_ID    0x06    /* Mask for the interrupt ID */
+
+#define UART_IIR_MSI   0x00    /* Modem status interrupt */
+#define UART_IIR_THRI  0x02    /* Transmitter holding register empty */
+#define UART_IIR_RDI   0x04    /* Receiver data interrupt */
+#define UART_IIR_RLSI  0x06    /* Receiver line status interrupt */
+
+/*
+ * These are the definitions for the Modem Control Register
+ */
+#define UART_MCR_LOOP  0x10    /* Enable loopback test mode */
+#define UART_MCR_OUT2  0x08    /* Out2 complement */
+#define UART_MCR_OUT1  0x04    /* Out1 complement */
+#define UART_MCR_RTS   0x02    /* RTS complement */
+#define UART_MCR_DTR   0x01    /* DTR complement */
+
+/*
+ * These are the definitions for the Modem Status Register
+ */
+#define UART_MSR_DCD   0x80    /* Data Carrier Detect */
+#define UART_MSR_RI    0x40    /* Ring Indicator */
+#define UART_MSR_DSR   0x20    /* Data Set Ready */
+#define UART_MSR_CTS   0x10    /* Clear to Send */
+#define UART_MSR_DDCD  0x08    /* Delta DCD */
+#define UART_MSR_TERI  0x04    /* Trailing edge ring indicator */
+#define UART_MSR_DDSR  0x02    /* Delta DSR */
+#define UART_MSR_DCTS  0x01    /* Delta CTS */
+#define UART_MSR_ANY_DELTA 0x0F        /* Any of the delta bits! */
+
+#define UART_LSR_TEMT  0x40    /* Transmitter empty */
+#define UART_LSR_THRE  0x20    /* Transmit-hold-register empty */
+#define UART_LSR_BI    0x10    /* Break interrupt indicator */
+#define UART_LSR_FE    0x08    /* Frame error indicator */
+#define UART_LSR_PE    0x04    /* Parity error indicator */
+#define UART_LSR_OE    0x02    /* Overrun error indicator */
+#define UART_LSR_DR    0x01    /* Receiver data ready */
+
+struct SerialState {
+    uint16_t divider;
+    uint8_t rbr; /* receive register */
+    uint8_t ier;
+    uint8_t iir; /* read only */
+    uint8_t lcr;
+    uint8_t mcr;
+    uint8_t lsr; /* read only */
+    uint8_t msr; /* read only */
+    uint8_t scr;
+    /* NOTE: this hidden state is necessary for tx irq generation as
+       it can be reset while reading iir */
+    int thr_ipending;
+    qemu_irq irq;
+    CharDriverState *chr;
+    int last_break_enable;
+    target_phys_addr_t base;
+    int it_shift;
+};
+
+static void serial_update_irq(SerialState *s)
+{
+    if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) {
+        s->iir = UART_IIR_RDI;
+    } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) {
+        s->iir = UART_IIR_THRI;
+    } else {
+        s->iir = UART_IIR_NO_INT;
+    }
+    if (s->iir != UART_IIR_NO_INT) {
+        qemu_irq_raise(s->irq);
+    } else {
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static void serial_update_parameters(SerialState *s)
+{
+#ifndef IOEMU
+    int speed, parity, data_bits, stop_bits;
+    QEMUSerialSetParams ssp;
+
+    if (s->lcr & 0x08) {
+        if (s->lcr & 0x10)
+            parity = 'E';
+        else
+            parity = 'O';
+    } else {
+            parity = 'N';
+    }
+    if (s->lcr & 0x04)
+        stop_bits = 2;
+    else
+        stop_bits = 1;
+    data_bits = (s->lcr & 0x03) + 5;
+    if (s->divider == 0)
+        return;
+    speed = 115200 / s->divider;
+    ssp.speed = speed;
+    ssp.parity = parity;
+    ssp.data_bits = data_bits;
+    ssp.stop_bits = stop_bits;
+    qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+#if 0
+    printf("speed=%d parity=%c data=%d stop=%d\n",
+           speed, parity, data_bits, stop_bits);
+#endif
+#endif
+}
+
+
+static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    SerialState *s = opaque;
+    unsigned char ch;
+
+    addr &= 7;
+#ifdef DEBUG_SERIAL
+    printf("serial: write addr=0x%02x val=0x%02x\n", addr, val);
+#endif
+    switch(addr) {
+    default:
+    case 0:
+        if (s->lcr & UART_LCR_DLAB) {
+            s->divider = (s->divider & 0xff00) | val;
+            serial_update_parameters(s);
+        } else {
+            s->thr_ipending = 0;
+            s->lsr &= ~UART_LSR_THRE;
+            serial_update_irq(s);
+            ch = val;
+            qemu_chr_write(s->chr, &ch, 1);
+            s->thr_ipending = 1;
+            s->lsr |= UART_LSR_THRE;
+            s->lsr |= UART_LSR_TEMT;
+            serial_update_irq(s);
+        }
+        break;
+    case 1:
+        if (s->lcr & UART_LCR_DLAB) {
+            s->divider = (s->divider & 0x00ff) | (val << 8);
+            serial_update_parameters(s);
+        } else {
+            s->ier = val & 0x0f;
+            if (s->lsr & UART_LSR_THRE) {
+                s->thr_ipending = 1;
+            }
+            serial_update_irq(s);
+        }
+        break;
+    case 2:
+        break;
+    case 3:
+        {
+            int break_enable;
+            s->lcr = val;
+            serial_update_parameters(s);
+            break_enable = (val >> 6) & 1;
+            if (break_enable != s->last_break_enable) {
+                s->last_break_enable = break_enable;
+                qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
+                               &break_enable);
+            }
+        }
+        break;
+    case 4:
+        s->mcr = val & 0x1f;
+        break;
+    case 5:
+        break;
+    case 6:
+        break;
+    case 7:
+        s->scr = val;
+        break;
+    }
+}
+
+static uint32_t serial_ioport_read(void *opaque, uint32_t addr)
+{
+    SerialState *s = opaque;
+    uint32_t ret;
+
+    addr &= 7;
+    switch(addr) {
+    default:
+    case 0:
+        if (s->lcr & UART_LCR_DLAB) {
+            ret = s->divider & 0xff;
+        } else {
+            ret = s->rbr;
+            s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
+            serial_update_irq(s);
+        }
+        break;
+    case 1:
+        if (s->lcr & UART_LCR_DLAB) {
+            ret = (s->divider >> 8) & 0xff;
+        } else {
+            ret = s->ier;
+        }
+        break;
+    case 2:
+        ret = s->iir;
+        /* reset THR pending bit */
+        if ((ret & 0x7) == UART_IIR_THRI)
+            s->thr_ipending = 0;
+        serial_update_irq(s);
+        break;
+    case 3:
+        ret = s->lcr;
+        break;
+    case 4:
+        ret = s->mcr;
+        break;
+    case 5:
+        ret = s->lsr;
+        break;
+    case 6:
+        if (s->mcr & UART_MCR_LOOP) {
+            /* in loopback, the modem output pins are connected to the
+               inputs */
+            ret = (s->mcr & 0x0c) << 4;
+            ret |= (s->mcr & 0x02) << 3;
+            ret |= (s->mcr & 0x01) << 5;
+        } else {
+            ret = s->msr;
+        }
+        break;
+    case 7:
+        ret = s->scr;
+        break;
+    }
+#ifdef DEBUG_SERIAL
+    printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret);
+#endif
+    return ret;
+}
+
+int serial_can_receive(SerialState *s)
+{
+    return !(s->lsr & UART_LSR_DR);
+}
+
+void serial_receive_byte(SerialState *s, int ch)
+{
+    s->rbr = ch;
+    s->lsr |= UART_LSR_DR;
+    serial_update_irq(s);
+}
+
+static void serial_receive_break(SerialState *s)
+{
+    s->rbr = 0;
+    s->lsr |= UART_LSR_BI | UART_LSR_DR;
+    serial_update_irq(s);
+}
+
+int serial_can_receive1(void *opaque)
+{
+    SerialState *s = opaque;
+    return serial_can_receive(s);
+}
+
+void serial_receive1(void *opaque, const uint8_t *buf, int size)
+{
+    SerialState *s = opaque;
+    serial_receive_byte(s, buf[0]);
+}
+
+void serial_event(void *opaque, int event)
+{
+    SerialState *s = opaque;
+    if (event == CHR_EVENT_BREAK)
+        serial_receive_break(s);
+}
+
+#if 0
+static void serial_save(QEMUFile *f, void *opaque)
+{
+    SerialState *s = opaque;
+
+    qemu_put_be16s(f,&s->divider);
+    qemu_put_8s(f,&s->rbr);
+    qemu_put_8s(f,&s->ier);
+    qemu_put_8s(f,&s->iir);
+    qemu_put_8s(f,&s->lcr);
+    qemu_put_8s(f,&s->mcr);
+    qemu_put_8s(f,&s->lsr);
+    qemu_put_8s(f,&s->msr);
+    qemu_put_8s(f,&s->scr);
+}
+
+static int serial_load(QEMUFile *f, void *opaque, int version_id)
+{
+    SerialState *s = opaque;
+
+    if(version_id > 2)
+        return -EINVAL;
+
+    if (version_id >= 2)
+        qemu_get_be16s(f, &s->divider);
+    else
+        s->divider = qemu_get_byte(f);
+    qemu_get_8s(f,&s->rbr);
+    qemu_get_8s(f,&s->ier);
+    qemu_get_8s(f,&s->iir);
+    qemu_get_8s(f,&s->lcr);
+    qemu_get_8s(f,&s->mcr);
+    qemu_get_8s(f,&s->lsr);
+    qemu_get_8s(f,&s->msr);
+    qemu_get_8s(f,&s->scr);
+
+    return 0;
+}
+#endif
+
+/* If fd is zero, it means that the serial device uses the console */
+SerialState *serial_init(int base, qemu_irq irq, CharDriverState *chr)
+{
+    SerialState *s;
+
+    s = qemu_mallocz(sizeof(SerialState));
+    if (!s)
+        return NULL;
+    s->irq = irq;
+    s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
+    s->iir = UART_IIR_NO_INT;
+    s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
+
+    s->chr = chr;
+
+    register_savevm("serial", base, 2, serial_save, serial_load, s);
+
+    register_ioport_write(base, 8, 1, serial_ioport_write, s);
+    register_ioport_read(base, 8, 1, serial_ioport_read, s);
+
+    qemu_chr_add_handlers(chr, serial_can_receive1, serial_receive1,
+                          serial_event, s);
+
+    return s;
+}
+
+#if 0
+/* Memory mapped interface */
+uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr)
+{
+    SerialState *s = opaque;
+
+    return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFF;
+}
+
+void serial_mm_writeb (void *opaque,
+                       target_phys_addr_t addr, uint32_t value)
+{
+    SerialState *s = opaque;
+
+    serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFF);
+}
+
+uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr)
+{
+    SerialState *s = opaque;
+    uint32_t val;
+
+    val = serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF;
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = bswap16(val);
+#endif
+    return val;
+}
+
+void serial_mm_writew (void *opaque,
+                       target_phys_addr_t addr, uint32_t value)
+{
+    SerialState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+    value = bswap16(value);
+#endif
+    serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFFFF);
+}
+
+uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr)
+{
+    SerialState *s = opaque;
+    uint32_t val;
+
+    val = serial_ioport_read(s, (addr - s->base) >> s->it_shift);
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = bswap32(val);
+#endif
+    return val;
+}
+
+void serial_mm_writel (void *opaque,
+                       target_phys_addr_t addr, uint32_t value)
+{
+    SerialState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+    value = bswap32(value);
+#endif
+    serial_ioport_write(s, (addr - s->base) >> s->it_shift, value);
+}
+
+static CPUReadMemoryFunc *serial_mm_read[] = {
+    &serial_mm_readb,
+    &serial_mm_readw,
+    &serial_mm_readl,
+};
+
+static CPUWriteMemoryFunc *serial_mm_write[] = {
+    &serial_mm_writeb,
+    &serial_mm_writew,
+    &serial_mm_writel,
+};
+
+SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
+                             qemu_irq irq, CharDriverState *chr,
+                             int ioregister)
+{
+    SerialState *s;
+    int s_io_memory;
+
+    s = qemu_mallocz(sizeof(SerialState));
+    if (!s)
+        return NULL;
+    s->irq = irq;
+    s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
+    s->iir = UART_IIR_NO_INT;
+    s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
+    s->base = base;
+    s->it_shift = it_shift;
+
+    register_savevm("serial", base, 2, serial_save, serial_load, s);
+
+    if (ioregister) {
+        s_io_memory = cpu_register_io_memory(0, serial_mm_read,
+                                             serial_mm_write, s);
+        cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
+    }
+    s->chr = chr;
+    qemu_chr_add_handlers(chr, serial_can_receive1, serial_receive1,
+                          serial_event, s);
+    return s;
+}
+#endif
diff -r 092232fa1fbd extras/stubfw/ioemu/vl.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/ioemu/vl.c  Sun Nov 18 07:14:31 2007 +0100
@@ -0,0 +1,87 @@
+#include "vl.h"
+
+/***********************************************************/
+/* character device */
+
+void qemu_chr_event(CharDriverState *s, int event)
+{
+    if (!s->chr_event)
+        return;
+    s->chr_event(s->handler_opaque, event);
+}
+
+#ifndef IOEMU
+
+static void qemu_chr_reset_bh(void *opaque)
+{
+    CharDriverState *s = opaque;
+    qemu_chr_event(s, CHR_EVENT_RESET);
+    qemu_bh_delete(s->bh);
+    s->bh = NULL;
+}
+#endif
+
+void qemu_chr_reset(CharDriverState *s)
+{
+#ifndef IOEMU
+    if (s->bh == NULL) {
+       s->bh = qemu_bh_new(qemu_chr_reset_bh, s);
+       qemu_bh_schedule(s->bh);
+    }
+#endif
+}
+
+int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len)
+{
+    return s->chr_write(s, buf, len);
+}
+
+int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg)
+{
+    if (!s->chr_ioctl)
+        return -ENOTSUP;
+    return s->chr_ioctl(s, cmd, arg);
+}
+
+int qemu_chr_can_read(CharDriverState *s)
+{
+    if (!s->chr_can_read)
+        return 0;
+    return s->chr_can_read(s->handler_opaque);
+}
+
+void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len)
+{
+    s->chr_read(s->handler_opaque, buf, len);
+}
+
+
+void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
+{
+    char buf[4096];
+    va_list ap;
+    va_start(ap, fmt);
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+    qemu_chr_write(s, buf, strlen(buf));
+    va_end(ap);
+}
+
+void qemu_chr_send_event(CharDriverState *s, int event)
+{
+    if (s->chr_send_event)
+        s->chr_send_event(s, event);
+}
+
+void qemu_chr_add_handlers(CharDriverState *s,
+                           IOCanRWHandler *fd_can_read,
+                           IOReadHandler *fd_read,
+                           IOEventHandler *fd_event,
+                           void *opaque)
+{
+    s->chr_can_read = fd_can_read;
+    s->chr_read = fd_read;
+    s->chr_event = fd_event;
+    s->handler_opaque = opaque;
+    if (s->chr_update_read_handler)
+        s->chr_update_read_handler(s);
+}
diff -r 092232fa1fbd extras/stubfw/ioemu/vl.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/ioemu/vl.h  Sun Nov 18 08:05:22 2007 +0100
@@ -0,0 +1,515 @@
+#include "lib.h"
+#include "types.h"
+#include "errno.h"
+#include "../vbd.h"
+
+#define IOEMU
+#define TARGET_PHYS_ADDR_BITS 64
+#define QEMU_VERSION "IOemu"
+#define TARGET_FMT_plx "%p"
+#define TARGET_FMT_lx "%016lx"
+#define PRIo64 "lo"
+#define PRIx64 "lx"
+#define PRIu64 "lu"
+#define PRId64 "ld"
+
+typedef uint64_t target_phys_addr_t;
+typedef uint64_t target_ulong; 
+typedef int64_t target_long; 
+
+extern int printf (const char *str, ...);
+extern void term_printf (const char *str, ...);
+//void pstrcpy(char *buf, int buf_size, const char *str);
+
+static inline uint16_t cpu_to_le16(uint16_t v)
+{
+  return v;
+}
+
+static inline uint32_t cpu_to_le32(uint32_t v)
+{
+  return v;
+}
+
+static inline uint16_t le16_to_cpu(uint16_t v)
+{
+  return v;
+}
+
+static inline uint32_t le32_to_cpu(uint32_t v)
+{
+  return v;
+}
+
+static inline void cpu_to_be16wu(uint16_t *p, uint16_t v)
+{
+    uint8_t *p1 = (uint8_t *)p;
+
+    p1[0] = v >> 8;
+    p1[1] = v;
+}
+
+static inline void cpu_to_be32wu(uint32_t *p, uint32_t v)
+{
+    uint8_t *p1 = (uint8_t *)p;
+
+    p1[0] = v >> 24;
+    p1[1] = v >> 16;
+    p1[2] = v >> 8;
+    p1[3] = v;
+}
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
+void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
+                            int len, int is_write);
+static inline void cpu_physical_memory_read(target_phys_addr_t addr,
+                                            uint8_t *buf, int len)
+{
+    cpu_physical_memory_rw(addr, buf, len, 0);
+}
+static inline void cpu_physical_memory_write(target_phys_addr_t addr,
+                                             const uint8_t *buf, int len)
+{
+    cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1);
+}
+
+#define ldub_raw(ADDR) (*((unsigned char*)(ADDR)))
+#define lduw_raw(ADDR) (*((unsigned short*)(ADDR)))
+#define ldl_raw(ADDR) (*((unsigned int*)(ADDR)))
+#define ldq_raw(ADDR) (*((unsigned long*)(ADDR)))
+
+void cpu_outb(int addr, int val);
+void cpu_outw(int addr, int val);
+void cpu_outl(int addr, int val);
+int cpu_inb(int addr);
+int cpu_inw(int addr);
+int cpu_inl(int addr);
+
+void init_ioports(void);
+
+#define register_savevm(NAME,A,B,S,L,D)
+
+/* async I/O support */
+
+typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
+typedef int IOCanRWHandler(void *opaque);
+typedef void IOHandler(void *opaque);
+
+/* character device */
+
+#define CHR_EVENT_BREAK 0 /* serial break char */
+#define CHR_EVENT_FOCUS 1 /* focus to this terminal (modal input needed) */
+#define CHR_EVENT_RESET 2 /* new connection established */
+
+
+#define CHR_IOCTL_SERIAL_SET_PARAMS   1
+typedef struct {
+    int speed;
+    int parity;
+    int data_bits;
+    int stop_bits;
+} QEMUSerialSetParams;
+
+#define CHR_IOCTL_SERIAL_SET_BREAK    2
+
+#define CHR_IOCTL_PP_READ_DATA        3
+#define CHR_IOCTL_PP_WRITE_DATA       4
+#define CHR_IOCTL_PP_READ_CONTROL     5
+#define CHR_IOCTL_PP_WRITE_CONTROL    6
+#define CHR_IOCTL_PP_READ_STATUS      7
+#define CHR_IOCTL_PP_EPP_READ_ADDR    8
+#define CHR_IOCTL_PP_EPP_READ         9
+#define CHR_IOCTL_PP_EPP_WRITE_ADDR  10
+#define CHR_IOCTL_PP_EPP_WRITE       11
+
+typedef void IOEventHandler(void *opaque, int event);
+
+typedef struct CharDriverState {
+    int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len);
+    void (*chr_update_read_handler)(struct CharDriverState *s);
+    int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg);
+    IOEventHandler *chr_event;
+    IOCanRWHandler *chr_can_read;
+    IOReadHandler *chr_read;
+    void *handler_opaque;
+    void (*chr_send_event)(struct CharDriverState *chr, int event);
+    void (*chr_close)(struct CharDriverState *chr);
+    void *opaque;
+    int focus;
+  //    QEMUBH *bh;
+} CharDriverState;
+
+CharDriverState *qemu_chr_open(const char *filename);
+void qemu_chr_printf(CharDriverState *s, const char *fmt, ...);
+int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len);
+void qemu_chr_send_event(CharDriverState *s, int event);
+void qemu_chr_add_handlers(CharDriverState *s,
+                           IOCanRWHandler *fd_can_read,
+                           IOReadHandler *fd_read,
+                           IOEventHandler *fd_event,
+                           void *opaque);
+int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg);
+void qemu_chr_reset(CharDriverState *s);
+int qemu_chr_can_read(CharDriverState *s);
+void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len);
+
+void qemu_chr_event(CharDriverState *s, int event);
+
+/* IRQ.  */
+/* Generic IRQ/GPIO pin infrastructure.  */
+typedef void SetIRQFunc(void *opaque, int irq_num, int level);
+
+typedef void (*qemu_irq_handler)(void *opaque, int n, int level);
+
+typedef struct IRQState *qemu_irq;
+
+void qemu_set_irq(qemu_irq irq, int level);
+
+static inline void qemu_irq_raise(qemu_irq irq)
+{
+    qemu_set_irq(irq, 1);
+}
+
+static inline void qemu_irq_lower(qemu_irq irq)
+{
+    qemu_set_irq(irq, 0);
+}
+
+/* Returns an array of N IRQs.  */
+qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n);
+
+/* Returns a new IRQ with opposite polarity.  */
+qemu_irq qemu_irq_invert(qemu_irq irq);
+
+/* Serial.  */
+
+typedef struct SerialState SerialState;
+SerialState *serial_init(int base, qemu_irq irq, CharDriverState *chr);
+
+/* mc146818rtc.c */
+
+typedef struct RTCState RTCState;
+
+RTCState *rtc_init(int base, qemu_irq irq);
+RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq);
+void rtc_set_memory(RTCState *s, int addr, int val);
+//void rtc_set_date(RTCState *s, const struct tm *tm);
+
+void *qemu_mallocz(size_t size);
+
+/* ISA bus */
+
+extern target_phys_addr_t isa_mem_base;
+
+typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data);
+typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address);
+
+int register_ioport_read(int start, int length, int size,
+                         IOPortReadFunc *func, void *opaque);
+int register_ioport_write(int start, int length, int size,
+                          IOPortWriteFunc *func, void *opaque);
+void isa_unassign_ioport(int start, int length);
+
+void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size);
+
+/* PCI bus */
+
+extern target_phys_addr_t pci_mem_base;
+
+typedef struct PCIBus PCIBus;
+typedef struct PCIDevice PCIDevice;
+
+typedef void PCIConfigWriteFunc(PCIDevice *pci_dev,
+                                uint32_t address, uint32_t data, int len);
+typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev,
+                                   uint32_t address, int len);
+typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num,
+                                uint32_t addr, uint32_t size, int type);
+
+#define PCI_ADDRESS_SPACE_MEM          0x00
+#define PCI_ADDRESS_SPACE_IO           0x01
+#define PCI_ADDRESS_SPACE_MEM_PREFETCH 0x08
+
+typedef struct PCIIORegion {
+    uint32_t addr; /* current PCI mapping address. -1 means not mapped */
+    uint32_t size;
+    uint8_t type;
+    PCIMapIORegionFunc *map_func;
+} PCIIORegion;
+
+#define PCI_ROM_SLOT 6
+#define PCI_NUM_REGIONS 7
+
+#define PCI_DEVICES_MAX 64
+
+#define PCI_VENDOR_ID          0x00    /* 16 bits */
+#define PCI_DEVICE_ID          0x02    /* 16 bits */
+#define PCI_COMMAND            0x04    /* 16 bits */
+#define  PCI_COMMAND_IO                0x1     /* Enable response in I/O space 
*/
+#define  PCI_COMMAND_MEMORY    0x2     /* Enable response in Memory space */
+#define PCI_CLASS_DEVICE        0x0a    /* Device class */
+#define PCI_INTERRUPT_LINE     0x3c    /* 8 bits */
+#define PCI_INTERRUPT_PIN      0x3d    /* 8 bits */
+#define PCI_MIN_GNT            0x3e    /* 8 bits */
+#define PCI_MAX_LAT            0x3f    /* 8 bits */
+
+struct PCIDevice {
+    /* PCI config space */
+    uint8_t config[256];
+
+    /* the following fields are read only */
+    PCIBus *bus;
+    int devfn;
+    char name[64];
+    PCIIORegion io_regions[PCI_NUM_REGIONS];
+
+    /* do not access the following fields */
+    PCIConfigReadFunc *config_read;
+    PCIConfigWriteFunc *config_write;
+    /* ??? This is a PC-specific hack, and should be removed.  */
+    int irq_index;
+
+    /* IRQ objects for the INTA-INTD pins.  */
+    qemu_irq *irq;
+
+    /* Current IRQ levels.  Used internally by the generic PCI code.  */
+    int irq_state[4];
+};
+
+PCIDevice *pci_register_device(PCIBus *bus, const char *name,
+                               int instance_size, int devfn,
+                               PCIConfigReadFunc *config_read,
+                               PCIConfigWriteFunc *config_write);
+
+void pci_register_io_region(PCIDevice *pci_dev, int region_num,
+                            uint32_t size, int type,
+                            PCIMapIORegionFunc *map_func);
+
+uint32_t pci_default_read_config(PCIDevice *d,
+                                 uint32_t address, int len);
+void pci_default_write_config(PCIDevice *d,
+                              uint32_t address, uint32_t val, int len);
+
+typedef void (*pci_set_irq_fn)(qemu_irq *pic, int irq_num, int level);
+typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
+PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
+                         qemu_irq *pic, int devfn_min, int nirq);
+
+void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len);
+uint32_t pci_data_read(void *opaque, uint32_t addr, int len);
+int pci_bus_num(PCIBus *s);
+void pci_for_each_device(int bus_num, void (*fn)(PCIDevice *d));
+
+void pci_info(void);
+PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id,
+                        pci_map_irq_fn map_irq, const char *name);
+
+/* prep_pci.c */
+PCIBus *pci_prep_init(qemu_irq *pic);
+
+/* piix_pci.c */
+PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic);
+void i440fx_set_smm(PCIDevice *d, int val);
+int piix4_init(PCIBus *bus, int devfn);
+
+/* Block drivers.  */
+/* block.c */
+typedef struct BlockDriverState BlockDriverState;
+typedef struct BlockDriver BlockDriver;
+
+extern BlockDriver bdrv_raw;
+extern BlockDriver bdrv_host_device;
+extern BlockDriver bdrv_cow;
+extern BlockDriver bdrv_qcow;
+extern BlockDriver bdrv_vmdk;
+extern BlockDriver bdrv_cloop;
+extern BlockDriver bdrv_dmg;
+extern BlockDriver bdrv_bochs;
+extern BlockDriver bdrv_vpc;
+extern BlockDriver bdrv_vvfat;
+extern BlockDriver bdrv_qcow2;
+extern BlockDriver bdrv_parallels;
+
+typedef struct BlockDriverInfo {
+    /* in bytes, 0 if irrelevant */
+    int cluster_size;
+    /* offset at which the VM state can be saved (0 if not possible) */
+    int64_t vm_state_offset;
+} BlockDriverInfo;
+
+typedef struct QEMUSnapshotInfo {
+    char id_str[128]; /* unique snapshot id */
+    /* the following fields are informative. They are not needed for
+       the consistency of the snapshot */
+    char name[256]; /* user choosen name */
+    uint32_t vm_state_size; /* VM state info size */
+    uint32_t date_sec; /* UTC date of the snapshot */
+    uint32_t date_nsec;
+    uint64_t vm_clock_nsec; /* VM clock relative to boot */
+} QEMUSnapshotInfo;
+
+#define BDRV_O_RDONLY      0x0000
+#define BDRV_O_RDWR        0x0002
+#define BDRV_O_ACCESS      0x0003
+#define BDRV_O_CREAT       0x0004 /* create an empty file */
+#define BDRV_O_SNAPSHOT    0x0008 /* open the file read only and save writes 
in a snapshot */
+#define BDRV_O_FILE        0x0010 /* open as a raw file (do not try to
+                                     use a disk image format on top of
+                                     it (default for
+                                     bdrv_file_open()) */
+
+void bdrv_init(void);
+BlockDriver *bdrv_find_format(const char *format_name);
+int bdrv_create(BlockDriver *drv,
+                const char *filename, int64_t size_in_sectors,
+                const char *backing_file, int flags);
+BlockDriverState *bdrv_new(const char *device_name);
+void bdrv_delete(BlockDriverState *bs);
+int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
+int bdrv_open(BlockDriverState *bs, const char *filename, int flags);
+int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
+               BlockDriver *drv);
+int bdrv_open_vbd(BlockDriverState *bs, struct vbd_info *info, int flags);
+void bdrv_close(BlockDriverState *bs);
+int bdrv_read(BlockDriverState *bs, int64_t sector_num,
+              uint8_t *buf, int nb_sectors);
+int bdrv_write(BlockDriverState *bs, int64_t sector_num,
+               const uint8_t *buf, int nb_sectors);
+int bdrv_pread(BlockDriverState *bs, int64_t offset,
+               void *buf, int count);
+int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
+                const void *buf, int count);
+int bdrv_truncate(BlockDriverState *bs, int64_t offset);
+int64_t bdrv_getlength(BlockDriverState *bs);
+void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr);
+int bdrv_commit(BlockDriverState *bs);
+void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size);
+/* async block I/O */
+typedef struct BlockDriverAIOCB BlockDriverAIOCB;
+typedef void BlockDriverCompletionFunc(void *opaque, int ret);
+
+BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
+                                uint8_t *buf, int nb_sectors,
+                                BlockDriverCompletionFunc *cb, void *opaque);
+BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num,
+                                 const uint8_t *buf, int nb_sectors,
+                                 BlockDriverCompletionFunc *cb, void *opaque);
+void bdrv_aio_cancel(BlockDriverAIOCB *acb);
+
+void qemu_aio_init(void);
+void qemu_aio_poll(void);
+void qemu_aio_flush(void);
+void qemu_aio_wait_start(void);
+void qemu_aio_wait(void);
+void qemu_aio_wait_end(void);
+
+int qemu_key_check(BlockDriverState *bs, const char *name);
+
+/* Ensure contents are flushed to disk.  */
+void bdrv_flush(BlockDriverState *bs);
+
+#define BDRV_TYPE_HD     0
+#define BDRV_TYPE_CDROM  1
+#define BDRV_TYPE_FLOPPY 2
+#define BIOS_ATA_TRANSLATION_AUTO   0
+#define BIOS_ATA_TRANSLATION_NONE   1
+#define BIOS_ATA_TRANSLATION_LBA    2
+#define BIOS_ATA_TRANSLATION_LARGE  3
+#define BIOS_ATA_TRANSLATION_RECHS  4
+
+void bdrv_set_geometry_hint(BlockDriverState *bs,
+                            int cyls, int heads, int secs);
+void bdrv_set_type_hint(BlockDriverState *bs, int type);
+void bdrv_set_translation_hint(BlockDriverState *bs, int translation);
+void bdrv_get_geometry_hint(BlockDriverState *bs,
+                            int *pcyls, int *pheads, int *psecs);
+int bdrv_get_type_hint(BlockDriverState *bs);
+int bdrv_get_translation_hint(BlockDriverState *bs);
+int bdrv_is_removable(BlockDriverState *bs);
+int bdrv_is_read_only(BlockDriverState *bs);
+int bdrv_is_inserted(BlockDriverState *bs);
+int bdrv_media_changed(BlockDriverState *bs);
+int bdrv_is_locked(BlockDriverState *bs);
+void bdrv_set_locked(BlockDriverState *bs, int locked);
+void bdrv_eject(BlockDriverState *bs, int eject_flag);
+void bdrv_set_change_cb(BlockDriverState *bs,
+                        void (*change_cb)(void *opaque), void *opaque);
+void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
+void bdrv_info(void);
+BlockDriverState *bdrv_find(const char *name);
+void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque);
+int bdrv_is_encrypted(BlockDriverState *bs);
+int bdrv_set_key(BlockDriverState *bs, const char *key);
+void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
+                         void *opaque);
+const char *bdrv_get_device_name(BlockDriverState *bs);
+int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
+                          const uint8_t *buf, int nb_sectors);
+int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
+
+void bdrv_get_backing_filename(BlockDriverState *bs,
+                               char *filename, int filename_size);
+int bdrv_snapshot_create(BlockDriverState *bs,
+                         QEMUSnapshotInfo *sn_info);
+int bdrv_snapshot_goto(BlockDriverState *bs,
+                       const char *snapshot_id);
+int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
+int bdrv_snapshot_list(BlockDriverState *bs,
+                       QEMUSnapshotInfo **psn_info);
+char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn);
+
+char *get_human_readable_size(char *buf, int buf_size, int64_t size);
+int path_is_absolute(const char *path);
+void path_combine(char *dest, int dest_size,
+                  const char *base_path,
+                  const char *filename);
+
+/* ide.c */
+#define MAX_DISKS 4
+
+extern BlockDriverState *bs_table[MAX_DISKS + 1];
+extern BlockDriverState *sd_bdrv;
+extern BlockDriverState *mtd_bdrv;
+
+void isa_ide_init(int iobase, int iobase2, qemu_irq irq,
+                  BlockDriverState *hd0, BlockDriverState *hd1);
+void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table,
+                         int secondary_ide_enabled);
+void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
+                        qemu_irq *pic);
+void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
+                        qemu_irq *pic);
+
+/* cdrom.c */
+int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
+int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num);
+
+#define SECTOR_BITS 9
+#define SECTOR_SIZE (1 << SECTOR_BITS)
+#define SECTOR_MASK (SECTOR_SIZE - 1)
+
+/* readline.c */
+typedef void ReadLineFunc(void *opaque, const char *str);
+
+extern int completion_index;
+void add_completion(const char *str);
+void readline_handle_byte(int ch);
+void readline_find_completion(const char *cmdline);
+const char *readline_get_history(unsigned int index);
+void readline_start(const char *prompt, int is_password,
+                    ReadLineFunc *readline_func, void *opaque);
+
+void kqemu_record_dump(void);
+
+
+/* IOemu.  */
+CharDriverState *qemu_chr_open_xc(void);
+CharDriverState *qemu_chr_open_mux(CharDriverState *drv);
+void monitor_init(CharDriverState *hd, int show_banner);
+
diff -r 092232fa1fbd extras/stubfw/main.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/main.c      Tue Nov 20 02:28:22 2007 +0100
@@ -0,0 +1,228 @@
+#include "types.h"
+#include "lib.h"
+#include "os.h"
+#include "console.h"
+#include "events.h"
+#include "ioemu/vl.h"
+#include "callback.h"
+#include "xenbus.h"
+#include "gnttab.h"
+
+struct IRQState {
+    qemu_irq_handler handler;
+    void *opaque;
+    int n;
+};
+
+extern void test_xenbus (void);
+extern void init_vbd (void);
+extern void vbd_test (void);
+extern qemu_irq *init_iosapic (void);
+/* Firmware memory map:
+   Start  at 0xff000000  size: 16MB (16GB - 16MB)
+   HOB    at 0xff200000  size:  1MB (16GB - 14MB)
+   Stacks at 0xff300000  size:  2MB
+   dev    at 0xff700000  size:  1MB
+   stubfw at 0xff800000  size:  2MB
+   NVRAM  at 0xffa00000  size: 64KB (16GB -  6MB) 
+   EFI    at 0xffe00000  size:  2MB
+*/
+
+
+#define BUG_ON(cond)
+
+extern int
+build_hob(unsigned long dom_mem_size, unsigned long vcpus,
+         unsigned long nvram_addr);
+
+void *serial1;
+static void *rtc;
+static PCIDevice *i440fx_state;
+static int piix4_devfn;
+static PCIBus *pci_bus;
+
+volatile struct shared_info *shared_info = (struct shared_info 
*)0x00000000e4008000UL;
+
+void
+setup_shared_info (void)
+{
+  struct xen_add_to_physmap xatp;
+
+  xatp.domid = DOMID_SELF;
+  xatp.idx = 0;
+  xatp.space = XENMAPSPACE_shared_info;
+  xatp.gpfn = ((unsigned long)shared_info) >> PAGE_SHIFT;
+  if (HYPERVISOR_add_to_physmap (&xatp))
+    BUG();
+}
+
+void
+exit (void)
+{
+  HYPERVISOR_shutdown(SHUTDOWN_poweroff);
+  while (1) ;
+}
+
+void
+dump_shared_info (void)
+{
+  int i;
+  printk ("evtchn mask - pending:\n");
+  for (i = 0; i < 8; i++)
+    printk (" %016lx %016lx\n",
+           shared_info->evtchn_mask[i], shared_info->evtchn_pending[i]);
+  for (i = 0; i < 1; i++)
+    {
+      volatile struct vcpu_info *info = &shared_info->vcpu_info[i];
+      printk ("vcpu %d: pending=%d mask=%d sel=%016lx\n",
+             i,
+             info->evtchn_upcall_pending,
+             info->evtchn_upcall_mask,
+             info->evtchn_pending_sel);
+    }
+}
+
+
+extern const char callback_entry;
+
+struct cb_status {
+  unsigned long status;
+  unsigned long arg1;
+  unsigned long arg2;
+  unsigned long arg3;
+};
+
+int ioemu_trace;
+
+struct cb_status
+ia64_callback (unsigned long cause,
+              unsigned long arg1, unsigned long arg2,
+              unsigned long arg3, unsigned long arg4,
+              unsigned long arg5,
+              struct ia64_cb_regs *regs)
+{
+  if (ioemu_trace)
+    printk ("call_back: cause=%lx, arg1=%lx, arg2=%lx, arg3=%lx, arg4=%lx\n",
+           cause, arg1, arg2, arg3, arg4);
+
+  if (cause == 0) {
+    do_hypervisor_callback ();
+    return ((struct cb_status){0,0,0,0});
+  }
+  else if (cause == 1) {
+    int sz = arg4 & 0x07;
+    int mode_r = arg4 & 0x80;
+    unsigned long paddr = arg1;
+
+    static int count;
+
+    if (++count == 400)
+      printk ("$$$ CALLBACK: ip = %lx paddr=%lx\n", regs->ip, paddr);
+
+    if (paddr >= 0x0e0000000 && paddr < 0x0e4000000) {
+      /* IO port.  */
+      unsigned int port = (((paddr >> 12) & 0x3fff) << 2) | (paddr & 0x03);
+      //printk ("ioport=0x%x\n", port);
+      switch (sz | (mode_r >> 4))
+       {
+       case 0x8:
+         arg2 = cpu_inb (port);
+         break;
+       case 0x9:
+         arg2 = cpu_inw (port);
+         break;
+       case 0xa:
+         arg2 = cpu_inl (port);
+         break;
+       case 0x0:
+         cpu_outb (port, arg2);
+         break;
+       case 0x1:
+         cpu_outw (port, arg2);
+         break;
+       case 0x2:
+         cpu_outl (port, arg2);
+         break;
+       default:
+         printk ("callback: io emul port=%lx data=%lx sz=%d %c ",
+                 port, arg2, 1 << sz, mode_r ? 'r' : 'w');
+         printk ("ip = %lx\n", regs->ip);
+         exit ();
+       }
+      return ((struct cb_status){1,arg4,arg2,0});
+    }
+    printk ("callback: io emul addr=%lx data=%lx sz=%d %c\n",
+           paddr, arg2, 1 << sz, mode_r ? 'r' : 'w');
+    printk ("ip = %lx\n", regs->ip);
+
+    exit();
+  }
+  else {
+    printk ("call_back: cause=%lx, arg1=%lx, arg2=%lx, arg3=%lx, arg4=%lx\n",
+           cause, arg1, arg2, arg3, arg4);
+    exit ();
+  }
+  return ((struct cb_status){0xff,0,0,0});
+}
+
+void cmain (unsigned long xstore_desc, unsigned long cons_desc,
+           unsigned long mem_mb, unsigned long nvcpu)
+{
+  qemu_irq *iosapic;
+  CharDriverState *chr;
+
+  setup_shared_info ();
+  init_events ();
+  init_console ((void *)(cons_desc & ~0xfffUL), cons_desc & 0xfff);
+
+  printk ("xstore: %lx\n", xstore_desc);
+  printk ("console: %lx\n", cons_desc);
+  printk ("mem_mb: %d, vcpus: %d\n", mem_mb, nvcpu);
+
+  shared_info->vcpu_info[0].evtchn_upcall_mask = 1;
+
+  HYPERVISOR_HVMSTUB_set_callback(&callback_entry, (void *)0xff300000);
+
+  dump_shared_info ();
+
+  init_xenbus ((void *)(xstore_desc & ~0xfffUL), xstore_desc & 0xfff);
+#if 0
+  test_xenbus ();
+  exit ();
+#endif
+  init_gnttab ();
+  bdrv_init ();
+  init_vbd ();
+
+  chr = qemu_chr_open_xc ();
+
+  // vbd_test ();
+  init_ioports ();
+
+  iosapic = init_iosapic ();
+
+  /* Set up devices.  */
+  pci_bus = i440fx_init(&i440fx_state, iosapic);
+  piix4_devfn = -1;
+  piix4_devfn = piix4_init(pci_bus, -1);
+  
+  //pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
+  pci_piix4_ide_init(pci_bus, bs_table, piix4_devfn + 1, iosapic);
+
+  serial1 = serial_init (0x3f8, iosapic[4], chr);
+  rtc = rtc_init (0x70, iosapic[8]);
+
+  pci_info ();
+
+  build_hob (mem_mb << 20, nvcpu, 0xffa00000UL);
+
+  /* psr= IA64_PSR_AC | IA64_PSR_BN  */
+  HYPERVISOR_HVMSTUB_fw_start(0x80000000ffffffb0UL,
+                             (1UL << 44) | (1UL << 3));
+
+  printk ("failed to start fw\n");
+  shared_info->vcpu_info[0].evtchn_upcall_mask = 0;
+
+  while (1)
+    ;
+}
diff -r 092232fa1fbd extras/stubfw/netfront.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/netfront.c  Wed Nov 14 02:19:13 2007 +0100
@@ -0,0 +1,456 @@
+/* Minimal network driver for Mini-OS. 
+ * Copyright (c) 2006-2007 Jacob Gorm Hansen, University of Copenhagen.
+ * Based on netfront.c from Xen Linux.
+ *
+ * Does not handle fragments or extras.
+ */
+
+#include <os.h>
+#include <xenbus.h>
+#include <events.h>
+#include <errno.h>
+#include <xen/io/netif.h>
+#include <gnttab.h>
+#include <xmalloc.h>
+#include <time.h>
+
+void init_rx_buffers(void);
+
+struct net_info {
+    struct netif_tx_front_ring tx;
+    struct netif_rx_front_ring rx;
+    int tx_ring_ref;
+    int rx_ring_ref;
+    unsigned int evtchn, local_port;
+
+} net_info;
+
+
+char* xenbus_printf(xenbus_transaction_t xbt,
+        char* node,char* path,
+        char* fmt,unsigned int arg)
+{
+    char fullpath[256];
+    char val[256];
+
+    sprintf(fullpath,"%s/%s",node,path);
+    sprintf(val,fmt,arg);
+    xenbus_write(xbt,fullpath,val);
+
+    return NULL;
+}
+
+
+#define NET_TX_RING_SIZE __RING_SIZE((struct netif_tx_sring *)0, PAGE_SIZE)
+#define NET_RX_RING_SIZE __RING_SIZE((struct netif_rx_sring *)0, PAGE_SIZE)
+#define GRANT_INVALID_REF 0
+
+
+unsigned short rx_freelist[NET_RX_RING_SIZE];
+unsigned short tx_freelist[NET_TX_RING_SIZE];
+
+struct net_buffer {
+    void* page;
+    int gref;
+};
+struct net_buffer rx_buffers[NET_RX_RING_SIZE];
+struct net_buffer tx_buffers[NET_TX_RING_SIZE];
+
+static inline void add_id_to_freelist(unsigned int id,unsigned short* freelist)
+{
+    freelist[id] = freelist[0];
+    freelist[0]  = id;
+}
+
+static inline unsigned short get_id_from_freelist(unsigned short* freelist)
+{
+    unsigned int id = freelist[0];
+    freelist[0] = freelist[id];
+    return id;
+}
+
+__attribute__((weak)) void netif_rx(unsigned char* data,int len)
+{
+    printk("%d bytes incoming at %p\n",len,data);
+}
+
+__attribute__((weak)) void net_app_main(void*si,unsigned char*mac) {}
+
+static inline int xennet_rxidx(RING_IDX idx)
+{
+    return idx & (NET_RX_RING_SIZE - 1);
+}
+
+void network_rx(void)
+{
+    struct net_info *np = &net_info;
+    RING_IDX rp,cons;
+    struct netif_rx_response *rx;
+
+
+moretodo:
+    rp = np->rx.sring->rsp_prod;
+    rmb(); /* Ensure we see queued responses up to 'rp'. */
+    cons = np->rx.rsp_cons;
+
+    int nr_consumed=0;
+    while ((cons != rp))
+    {
+        struct net_buffer* buf;
+        unsigned char* page;
+
+        rx = RING_GET_RESPONSE(&np->rx, cons);
+
+        if (rx->flags & NETRXF_extra_info)
+        {
+            printk("+++++++++++++++++++++ we have extras!\n");
+            continue;
+        }
+
+
+        if (rx->status == NETIF_RSP_NULL) continue;
+
+        int id = rx->id;
+
+        buf = &rx_buffers[id];
+        page = (unsigned char*)buf->page;
+        gnttab_end_access(buf->gref);
+
+        if(rx->status>0)
+        {
+            netif_rx(page+rx->offset,rx->status);
+        }
+
+        add_id_to_freelist(id,rx_freelist);
+
+        nr_consumed++;
+
+        ++cons;
+    }
+    np->rx.rsp_cons=rp;
+
+    int more;
+    RING_FINAL_CHECK_FOR_RESPONSES(&np->rx,more);
+    if(more) goto moretodo;
+
+    RING_IDX req_prod = np->rx.req_prod_pvt;
+
+    int i;
+    netif_rx_request_t *req;
+
+    for(i=0; i<nr_consumed; i++)
+    {
+        int id = xennet_rxidx(req_prod + i);
+        req = RING_GET_REQUEST(&np->rx, req_prod + i);
+        struct net_buffer* buf = &rx_buffers[id];
+        void* page = buf->page;
+
+        buf->gref = req->gref = 
+            gnttab_grant_access(0,virt_to_mfn(page),0);
+
+        req->id = id;
+    }
+
+    wmb();
+
+    np->rx.req_prod_pvt = req_prod + i;
+    
+    int notify;
+    RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
+    if (notify)
+        notify_remote_via_evtchn(np->evtchn);
+
+}
+
+void network_tx_buf_gc(void)
+{
+
+
+    RING_IDX cons, prod;
+    unsigned short id;
+    struct net_info *np = &net_info;
+
+    do {
+        prod = np->tx.sring->rsp_prod;
+        rmb(); /* Ensure we see responses up to 'rp'. */
+
+        for (cons = np->tx.rsp_cons; cons != prod; cons++) 
+        {
+            struct netif_tx_response *txrsp;
+
+            txrsp = RING_GET_RESPONSE(&np->tx, cons);
+            if (txrsp->status == NETIF_RSP_NULL)
+                continue;
+
+            id  = txrsp->id;
+            struct net_buffer* buf = &tx_buffers[id];
+            gnttab_end_access(buf->gref);
+            buf->gref=GRANT_INVALID_REF;
+
+            add_id_to_freelist(id,tx_freelist);
+        }
+
+        np->tx.rsp_cons = prod;
+
+        /*
+         * Set a new event, then check for race with update of tx_cons.
+         * Note that it is essential to schedule a callback, no matter
+         * how few tx_buffers are pending. Even if there is space in the
+         * transmit ring, higher layers may be blocked because too much
+         * data is outstanding: in such cases notification from Xen is
+         * likely to be the only kick that we'll get.
+         */
+        np->tx.sring->rsp_event =
+            prod + ((np->tx.sring->req_prod - prod) >> 1) + 1;
+        mb();
+    } while ((cons == prod) && (prod != np->tx.sring->rsp_prod));
+
+
+}
+
+void netfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
+{
+    int flags;
+
+    local_irq_save(flags);
+
+    network_tx_buf_gc();
+    network_rx();
+
+    local_irq_restore(flags);
+}
+
+char* backend;
+
+void init_netfront(void* si)
+{
+    xenbus_transaction_t xbt;
+    struct net_info* info = &net_info;
+    char* err;
+    char* message=NULL;
+    char nodename[] = "device/vif/0";
+    struct netif_tx_sring *txs;
+    struct netif_rx_sring *rxs;
+    int retry=0;
+    int i;
+    char* mac;
+    char* msg;
+
+    printk("************************ NETFRONT **********\n\n\n");
+
+    for(i=0;i<NET_TX_RING_SIZE;i++)
+    {
+        add_id_to_freelist(i,tx_freelist);
+        tx_buffers[i].page = (char*)alloc_page();
+    }
+
+    for(i=0;i<NET_RX_RING_SIZE;i++)
+    {
+        add_id_to_freelist(i,rx_freelist);
+        rx_buffers[i].page = (char*)alloc_page();
+    }
+
+    txs = (struct netif_tx_sring*) alloc_page();
+    rxs = (struct netif_rx_sring *) alloc_page();
+    memset(txs,0,PAGE_SIZE);
+    memset(rxs,0,PAGE_SIZE);
+
+
+    SHARED_RING_INIT(txs);
+    SHARED_RING_INIT(rxs);
+    FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE);
+    FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE);
+
+    info->tx_ring_ref = gnttab_grant_access(0,virt_to_mfn(txs),0);
+    info->rx_ring_ref = gnttab_grant_access(0,virt_to_mfn(rxs),0);
+
+    evtchn_alloc_unbound_t op;
+    op.dom = DOMID_SELF;
+    op.remote_dom = 0;
+    HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &op);
+    clear_evtchn(op.port);        /* Without, handler gets invoked now! */
+    info->local_port = bind_evtchn(op.port, netfront_handler, NULL);
+    info->evtchn=op.port;
+
+again:
+    err = xenbus_transaction_start(&xbt);
+    if (err) {
+        printk("starting transaction\n");
+    }
+
+    err = xenbus_printf(xbt, nodename, "tx-ring-ref","%u",
+                info->tx_ring_ref);
+    if (err) {
+        message = "writing tx ring-ref";
+        goto abort_transaction;
+    }
+    err = xenbus_printf(xbt, nodename, "rx-ring-ref","%u",
+                info->rx_ring_ref);
+    if (err) {
+        message = "writing rx ring-ref";
+        goto abort_transaction;
+    }
+    err = xenbus_printf(xbt, nodename,
+                "event-channel", "%u", info->evtchn);
+    if (err) {
+        message = "writing event-channel";
+        goto abort_transaction;
+    }
+
+    err = xenbus_printf(xbt, nodename, "request-rx-copy", "%u", 1);
+
+    if (err) {
+        message = "writing request-rx-copy";
+        goto abort_transaction;
+    }
+
+    err = xenbus_printf(xbt, nodename, "state", "%u",
+            4); /* connected */
+
+
+    err = xenbus_transaction_end(xbt, 0, &retry);
+    if (retry) {
+            goto again;
+        printk("completing transaction\n");
+    }
+
+    goto done;
+
+abort_transaction:
+    xenbus_transaction_end(xbt, 1, &retry);
+
+done:
+
+    msg = xenbus_read(XBT_NIL, "device/vif/0/backend", &backend);
+    msg = xenbus_read(XBT_NIL, "device/vif/0/mac", &mac);
+
+    if ((backend == NULL) || (mac == NULL)) {
+        struct evtchn_close op = { info->local_port };
+        printk("%s: backend/mac failed\n", __func__);
+        unbind_evtchn(info->local_port);
+        HYPERVISOR_event_channel_op(EVTCHNOP_close, &op);
+        return;
+    }
+
+    printk("backend at %s\n",backend);
+    printk("mac is %s\n",mac);
+
+    char path[256];
+    sprintf(path,"%s/state",backend);
+
+    xenbus_watch_path(XBT_NIL, path);
+
+    xenbus_wait_for_value(path,"4");
+
+    //free(backend);
+
+    printk("**************************\n");
+
+    init_rx_buffers();
+
+    unsigned char rawmac[6];
+        /* Special conversion specifier 'hh' needed for __ia64__. Without
+           this mini-os panics with 'Unaligned reference'. */
+    sscanf(mac,"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+            &rawmac[0],
+            &rawmac[1],
+            &rawmac[2],
+            &rawmac[3],
+            &rawmac[4],
+            &rawmac[5]);
+
+    net_app_main(si,rawmac);
+}
+
+void shutdown_netfront(void)
+{
+    //xenbus_transaction_t xbt;
+    char* err;
+    char nodename[] = "device/vif/0";
+
+    char path[256];
+
+    printk("close network: backend at %s\n",backend);
+
+    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6); /* closing */
+    sprintf(path,"%s/state",backend);
+
+    xenbus_wait_for_value(path,"6");
+
+    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 1);
+
+    xenbus_wait_for_value(path,"2");
+
+    unbind_all_ports();
+
+}
+
+
+void init_rx_buffers(void)
+{
+    struct net_info* np = &net_info;
+    int i, requeue_idx;
+    netif_rx_request_t *req;
+    int notify;
+
+    /* Rebuild the RX buffer freelist and the RX ring itself. */
+    for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) 
+    {
+        struct net_buffer* buf = &rx_buffers[requeue_idx];
+        req = RING_GET_REQUEST(&np->rx, requeue_idx);
+
+        buf->gref = req->gref = 
+            gnttab_grant_access(0,virt_to_mfn(buf->page),0);
+
+        req->id = requeue_idx;
+
+        requeue_idx++;
+    }
+
+    np->rx.req_prod_pvt = requeue_idx;
+
+    RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
+
+    if (notify) 
+        notify_remote_via_evtchn(np->evtchn);
+
+    np->rx.sring->rsp_event = np->rx.rsp_cons + 1;
+}
+
+
+void netfront_xmit(unsigned char* data,int len)
+{
+    int flags;
+    local_irq_save(flags);
+
+    struct net_info* info = &net_info;
+    struct netif_tx_request *tx;
+    RING_IDX i = info->tx.req_prod_pvt;
+    int notify;
+    int id = get_id_from_freelist(tx_freelist);
+    struct net_buffer* buf = &tx_buffers[id];
+    void* page = buf->page;
+
+    tx = RING_GET_REQUEST(&info->tx, i);
+
+    memcpy(page,data,len);
+
+    buf->gref = 
+        tx->gref = gnttab_grant_access(0,virt_to_mfn(page),0);
+
+    tx->offset=0;
+    tx->size = len;
+    tx->flags=0;
+    tx->id = id;
+    info->tx.req_prod_pvt = i + 1;
+
+    wmb();
+
+    RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->tx, notify);
+
+    if(notify) notify_remote_via_evtchn(info->evtchn);
+
+    network_tx_buf_gc();
+
+    local_irq_restore(flags);
+}
diff -r 092232fa1fbd extras/stubfw/printf.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/printf.c    Wed Nov 07 00:40:13 2007 +0100
@@ -0,0 +1,793 @@
+/* 
+ ****************************************************************************
+ * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
+ ****************************************************************************
+ *
+ *        File: printf.c
+ *      Author: Rolf Neugebauer (neugebar@xxxxxxxxxxxxx)
+ *     Changes: Grzegorz Milos (gm281@xxxxxxxxx) 
+ *              
+ *        Date: Aug 2003, Aug 2005
+ * 
+ * Environment: Xen Minimal OS
+ * Description: Library functions for printing
+ *              (freebsd port, mainly sys/subr_prf.c)
+ *
+ ****************************************************************************
+ *
+ *-
+ * Copyright (c) 1992, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/libkern/divdi3.c,v 1.6 1999/08/28 00:46:31 peter Exp $
+ */
+
+#if !defined HAVE_LIBC
+
+#include <os.h>
+#include <types.h>
+#include <hypervisor.h>
+#include <lib.h>
+#include <ctype.h>
+
+/**
+ * simple_strtoul - convert a string to an unsigned long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
+{
+    unsigned long result = 0,value;
+
+    if (!base) {
+        base = 10;
+        if (*cp == '0') {
+            base = 8;
+            cp++;
+            if ((*cp == 'x') && isxdigit(cp[1])) {
+                cp++;
+                base = 16;
+            }
+        }
+    }
+    while (isxdigit(*cp) &&
+           (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
+        result = result*base + value;
+        cp++;
+    }
+    if (endp)
+        *endp = (char *)cp;
+    return result;
+}
+
+/**
+ * simple_strtol - convert a string to a signed long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long simple_strtol(const char *cp,char **endp,unsigned int base)
+{
+    if(*cp=='-')
+        return -simple_strtoul(cp+1,endp,base);
+    return simple_strtoul(cp,endp,base);
+}
+
+/**
+ * simple_strtoull - convert a string to an unsigned long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int 
base)
+{
+    unsigned long long result = 0,value;
+
+    if (!base) {
+        base = 10;
+        if (*cp == '0') {
+            base = 8;
+            cp++;
+            if ((*cp == 'x') && isxdigit(cp[1])) {
+                cp++;
+                base = 16;
+            }
+        }
+    }
+    while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+                                                               ? toupper(*cp) 
: *cp)-'A'+10) < base) {
+        result = result*base + value;
+        cp++;
+    }
+    if (endp)
+        *endp = (char *)cp;
+    return result;
+}
+
+/**
+ * simple_strtoll - convert a string to a signed long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long long simple_strtoll(const char *cp,char **endp,unsigned int base)
+{
+    if(*cp=='-')
+        return -simple_strtoull(cp+1,endp,base);
+    return simple_strtoull(cp,endp,base);
+}
+
+static int skip_atoi(const char **s)
+{
+    int i=0;
+
+    while (isdigit(**s))
+        i = i*10 + *((*s)++) - '0';
+    return i;
+}
+
+#define ZEROPAD 1               /* pad with zero */
+#define SIGN    2               /* unsigned/signed long */
+#define PLUS    4               /* show plus */
+#define SPACE   8               /* space if plus */
+#define LEFT    16              /* left justified */
+#define SPECIAL 32              /* 0x */
+#define LARGE   64              /* use 'ABCDEF' instead of 'abcdef' */
+
+static char * number(char * buf, char * end, long long num, int base, int 
size, int precision, int type)
+{
+    char c,sign,tmp[66];
+    const char *digits;
+    const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+    const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+    int i;
+
+    digits = (type & LARGE) ? large_digits : small_digits;
+    if (type & LEFT)
+        type &= ~ZEROPAD;
+    if (base < 2 || base > 36)
+        return buf;
+    c = (type & ZEROPAD) ? '0' : ' ';
+    sign = 0;
+    if (type & SIGN) {
+        if (num < 0) {
+            sign = '-';
+            num = -num;
+            size--;
+        } else if (type & PLUS) {
+            sign = '+';
+            size--;
+        } else if (type & SPACE) {
+            sign = ' ';
+            size--;
+        }
+    }
+    if (type & SPECIAL) {
+        if (base == 16)
+            size -= 2;
+        else if (base == 8)
+            size--;
+    }
+    i = 0;
+    if (num == 0)
+        tmp[i++]='0';
+    else 
+    {
+        /* XXX KAF: force unsigned mod and div. */
+        unsigned long long num2=(unsigned long long)num;
+        unsigned int base2=(unsigned int)base;
+        while (num2 != 0) { tmp[i++] = digits[num2%base2]; num2 /= base2; }
+    }
+    if (i > precision)
+        precision = i;
+    size -= precision;
+    if (!(type&(ZEROPAD+LEFT))) {
+        while(size-->0) {
+            if (buf <= end)
+                *buf = ' ';
+            ++buf;
+        }
+    }
+    if (sign) {
+        if (buf <= end)
+            *buf = sign;
+        ++buf;
+    }
+    if (type & SPECIAL) {
+        if (base==8) {
+            if (buf <= end)
+                *buf = '0';
+            ++buf;
+        } else if (base==16) {
+            if (buf <= end)
+                *buf = '0';
+            ++buf;
+            if (buf <= end)
+                *buf = digits[33];
+            ++buf;
+        }
+    }
+    if (!(type & LEFT)) {
+        while (size-- > 0) {
+            if (buf <= end)
+                *buf = c;
+            ++buf;
+        }
+    }
+    while (i < precision--) {
+        if (buf <= end)
+            *buf = '0';
+        ++buf;
+    }
+    while (i-- > 0) {
+        if (buf <= end)
+            *buf = tmp[i];
+        ++buf;
+    }
+    while (size-- > 0) {
+        if (buf <= end)
+            *buf = ' ';
+        ++buf;
+    }
+    return buf;
+}
+
+/**
+* vsnprintf - Format a string and place it in a buffer
+* @buf: The buffer to place the result into
+* @size: The size of the buffer, including the trailing null space
+* @fmt: The format string to use
+* @args: Arguments for the format string
+*
+* Call this function if you are already dealing with a va_list.
+* You probably want snprintf instead.
+ */
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+    int len;
+    unsigned long long num;
+    int i, base;
+    char *str, *end, c;
+    const char *s;
+
+    int flags;          /* flags to number() */
+
+    int field_width;    /* width of output field */
+    int precision;              /* min. # of digits for integers; max
+                                   number of chars for from string */
+    int qualifier;              /* 'h', 'l', or 'L' for integer fields */
+                                /* 'z' support added 23/7/1999 S.H.    */
+                                /* 'z' changed to 'Z' --davidm 1/25/99 */
+
+    str = buf;
+    end = buf + size - 1;
+
+    if (end < buf - 1) {
+        end = ((void *) -1);
+        size = end - buf + 1;
+    }
+
+    for (; *fmt ; ++fmt) {
+        if (*fmt != '%') {
+            if (str <= end)
+                *str = *fmt;
+            ++str;
+            continue;
+        }
+
+        /* process flags */
+        flags = 0;
+    repeat:
+        ++fmt;          /* this also skips first '%' */
+        switch (*fmt) {
+        case '-': flags |= LEFT; goto repeat;
+        case '+': flags |= PLUS; goto repeat;
+        case ' ': flags |= SPACE; goto repeat;
+        case '#': flags |= SPECIAL; goto repeat;
+        case '0': flags |= ZEROPAD; goto repeat;
+        }
+
+        /* get field width */
+        field_width = -1;
+        if (isdigit(*fmt))
+            field_width = skip_atoi(&fmt);
+        else if (*fmt == '*') {
+            ++fmt;
+            /* it's the next argument */
+            field_width = va_arg(args, int);
+            if (field_width < 0) {
+                field_width = -field_width;
+                flags |= LEFT;
+            }
+        }
+
+        /* get the precision */
+        precision = -1;
+        if (*fmt == '.') {
+            ++fmt;
+            if (isdigit(*fmt))
+                precision = skip_atoi(&fmt);
+            else if (*fmt == '*') {
+                ++fmt;
+                          /* it's the next argument */
+                precision = va_arg(args, int);
+            }
+            if (precision < 0)
+                precision = 0;
+        }
+
+        /* get the conversion qualifier */
+        qualifier = -1;
+        if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') {
+            qualifier = *fmt;
+            ++fmt;
+            if (qualifier == 'l' && *fmt == 'l') {
+                qualifier = 'L';
+                ++fmt;
+            }
+        }
+        if (*fmt == 'q') {
+            qualifier = 'L';
+            ++fmt;
+        }
+
+        /* default base */
+        base = 10;
+
+        switch (*fmt) {
+        case 'c':
+            if (!(flags & LEFT)) {
+                while (--field_width > 0) {
+                    if (str <= end)
+                        *str = ' ';
+                    ++str;
+                }
+            }
+            c = (unsigned char) va_arg(args, int);
+            if (str <= end)
+                *str = c;
+            ++str;
+            while (--field_width > 0) {
+                if (str <= end)
+                    *str = ' ';
+                ++str;
+            }
+            continue;
+
+        case 's':
+            s = va_arg(args, char *);
+            if (!s)
+                s = "<NULL>";
+
+            len = strnlen(s, precision);
+
+            if (!(flags & LEFT)) {
+                while (len < field_width--) {
+                    if (str <= end)
+                        *str = ' ';
+                    ++str;
+                }
+            }
+            for (i = 0; i < len; ++i) {
+                if (str <= end)
+                    *str = *s;
+                ++str; ++s;
+            }
+            while (len < field_width--) {
+                if (str <= end)
+                    *str = ' ';
+                ++str;
+            }
+            continue;
+
+        case 'p':
+            if (field_width == -1) {
+                field_width = 2*sizeof(void *);
+                flags |= ZEROPAD;
+            }
+            str = number(str, end,
+                         (unsigned long) va_arg(args, void *),
+                         16, field_width, precision, flags);
+            continue;
+
+
+        case 'n':
+            /* FIXME:
+             * What does C99 say about the overflow case here? */
+            if (qualifier == 'l') {
+                long * ip = va_arg(args, long *);
+                *ip = (str - buf);
+            } else if (qualifier == 'Z') {
+                size_t * ip = va_arg(args, size_t *);
+                *ip = (str - buf);
+            } else {
+                int * ip = va_arg(args, int *);
+                *ip = (str - buf);
+            }
+            continue;
+
+        case '%':
+            if (str <= end)
+                *str = '%';
+            ++str;
+            continue;
+
+                        /* integer number formats - set up the flags and 
"break" */
+        case 'o':
+            base = 8;
+            break;
+
+        case 'X':
+            flags |= LARGE;
+        case 'x':
+            base = 16;
+            break;
+
+        case 'd':
+        case 'i':
+            flags |= SIGN;
+        case 'u':
+            break;
+
+        default:
+            if (str <= end)
+                *str = '%';
+            ++str;
+            if (*fmt) {
+                if (str <= end)
+                    *str = *fmt;
+                ++str;
+            } else {
+                --fmt;
+            }
+            continue;
+        }
+        if (qualifier == 'L')
+            num = va_arg(args, long long);
+        else if (qualifier == 'l') {
+            num = va_arg(args, unsigned long);
+            if (flags & SIGN)
+                num = (signed long) num;
+        } else if (qualifier == 'Z') {
+            num = va_arg(args, size_t);
+        } else if (qualifier == 'h') {
+            num = (unsigned short) va_arg(args, int);
+            if (flags & SIGN)
+                num = (signed short) num;
+        } else {
+            num = va_arg(args, unsigned int);
+            if (flags & SIGN)
+                num = (signed int) num;
+        }
+
+        str = number(str, end, num, base,
+                     field_width, precision, flags);
+    }
+    if (str <= end)
+        *str = '\0';
+    else if (size > 0)
+        /* don't write out a null byte if the buf size is zero */
+        *end = '\0';
+    /* the trailing null byte doesn't count towards the total
+     * ++str;
+     */
+    return str-buf;
+}
+
+/**
+ * snprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ */
+int snprintf(char * buf, size_t size, const char *fmt, ...)
+{
+    va_list args;
+    int i;
+
+    va_start(args, fmt);
+    i=vsnprintf(buf,size,fmt,args);
+    va_end(args);
+    return i;
+}
+
+/**
+ * vsprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want sprintf instead.
+ */
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+    return vsnprintf(buf, 0xFFFFFFFFUL, fmt, args);
+}
+
+
+/**
+ * sprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ */
+int sprintf(char * buf, const char *fmt, ...)
+{
+    va_list args;
+    int i;
+
+    va_start(args, fmt);
+    i=vsprintf(buf,fmt,args);
+    va_end(args);
+    return i;
+}
+
+/**
+ * vsscanf - Unformat a buffer into a list of arguments
+ * @buf:       input buffer
+ * @fmt:       format of buffer
+ * @args:      arguments
+ */
+int vsscanf(const char * buf, const char * fmt, va_list args)
+{
+       const char *str = buf;
+       char *next;
+       char digit;
+       int num = 0;
+       int qualifier;
+       int base;
+       int field_width;
+       int is_sign = 0;
+
+       while(*fmt && *str) {
+               /* skip any white space in format */
+               /* white space in format matchs any amount of
+                * white space, including none, in the input.
+                */
+               if (isspace(*fmt)) {
+                       while (isspace(*fmt))
+                               ++fmt;
+                       while (isspace(*str))
+                               ++str;
+               }
+
+               /* anything that is not a conversion must match exactly */
+               if (*fmt != '%' && *fmt) {
+                       if (*fmt++ != *str++)
+                               break;
+                       continue;
+               }
+
+               if (!*fmt)
+                       break;
+               ++fmt;
+               
+               /* skip this conversion.
+                * advance both strings to next white space
+                */
+               if (*fmt == '*') {
+                       while (!isspace(*fmt) && *fmt)
+                               fmt++;
+                       while (!isspace(*str) && *str)
+                               str++;
+                       continue;
+               }
+
+               /* get field width */
+               field_width = -1;
+               if (isdigit(*fmt))
+                       field_width = skip_atoi(&fmt);
+
+               /* get conversion qualifier */
+               qualifier = -1;
+               if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
+                   *fmt == 'Z' || *fmt == 'z') {
+                       qualifier = *fmt++;
+                       if (unlikely(qualifier == *fmt)) {
+                               if (qualifier == 'h') {
+                                       qualifier = 'H';
+                                       fmt++;
+                               } else if (qualifier == 'l') {
+                                       qualifier = 'L';
+                                       fmt++;
+                               }
+                       }
+               }
+               base = 10;
+               is_sign = 0;
+
+               if (!*fmt || !*str)
+                       break;
+
+               switch(*fmt++) {
+               case 'c':
+               {
+                       char *s = (char *) va_arg(args,char*);
+                       if (field_width == -1)
+                               field_width = 1;
+                       do {
+                               *s++ = *str++;
+                       } while (--field_width > 0 && *str);
+                       num++;
+               }
+               continue;
+               case 's':
+               {
+                       char *s = (char *) va_arg(args, char *);
+                       if(field_width == -1)
+                               field_width = INT_MAX;
+                       /* first, skip leading white space in buffer */
+                       while (isspace(*str))
+                               str++;
+
+                       /* now copy until next white space */
+                       while (*str && !isspace(*str) && field_width--) {
+                               *s++ = *str++;
+                       }
+                       *s = '\0';
+                       num++;
+               }
+               continue;
+               case 'n':
+                       /* return number of characters read so far */
+               {
+                       int *i = (int *)va_arg(args,int*);
+                       *i = str - buf;
+               }
+               continue;
+               case 'o':
+                       base = 8;
+                       break;
+               case 'x':
+               case 'X':
+                       base = 16;
+                       break;
+               case 'i':
+                        base = 0;
+               case 'd':
+                       is_sign = 1;
+               case 'u':
+                       break;
+               case '%':
+                       /* looking for '%' in str */
+                       if (*str++ != '%') 
+                               return num;
+                       continue;
+               default:
+                       /* invalid format; stop here */
+                       return num;
+               }
+
+               /* have some sort of integer conversion.
+                * first, skip white space in buffer.
+                */
+               while (isspace(*str))
+                       str++;
+
+               digit = *str;
+               if (is_sign && digit == '-')
+                       digit = *(str + 1);
+
+               if (!digit
+                    || (base == 16 && !isxdigit(digit))
+                    || (base == 10 && !isdigit(digit))
+                    || (base == 8 && (!isdigit(digit) || digit > '7'))
+                    || (base == 0 && !isdigit(digit)))
+                               break;
+
+               switch(qualifier) {
+               case 'H':       /* that's 'hh' in format */
+                       if (is_sign) {
+                               signed char *s = (signed char *) 
va_arg(args,signed char *);
+                               *s = (signed char) 
simple_strtol(str,&next,base);
+                       } else {
+                               unsigned char *s = (unsigned char *) 
va_arg(args, unsigned char *);
+                               *s = (unsigned char) simple_strtoul(str, &next, 
base);
+                       }
+                       break;
+               case 'h':
+                       if (is_sign) {
+                               short *s = (short *) va_arg(args,short *);
+                               *s = (short) simple_strtol(str,&next,base);
+                       } else {
+                               unsigned short *s = (unsigned short *) 
va_arg(args, unsigned short *);
+                               *s = (unsigned short) simple_strtoul(str, 
&next, base);
+                       }
+                       break;
+               case 'l':
+                       if (is_sign) {
+                               long *l = (long *) va_arg(args,long *);
+                               *l = simple_strtol(str,&next,base);
+                       } else {
+                               unsigned long *l = (unsigned long*) 
va_arg(args,unsigned long*);
+                               *l = simple_strtoul(str,&next,base);
+                       }
+                       break;
+               case 'L':
+                       if (is_sign) {
+                               long long *l = (long long*) va_arg(args,long 
long *);
+                               *l = simple_strtoll(str,&next,base);
+                       } else {
+                               unsigned long long *l = (unsigned long long*) 
va_arg(args,unsigned long long*);
+                               *l = simple_strtoull(str,&next,base);
+                       }
+                       break;
+               case 'Z':
+               case 'z':
+               {
+                       size_t *s = (size_t*) va_arg(args,size_t*);
+                       *s = (size_t) simple_strtoul(str,&next,base);
+               }
+               break;
+               default:
+                       if (is_sign) {
+                               int *i = (int *) va_arg(args, int*);
+                               *i = (int) simple_strtol(str,&next,base);
+                       } else {
+                               unsigned int *i = (unsigned int*) va_arg(args, 
unsigned int*);
+                               *i = (unsigned int) 
simple_strtoul(str,&next,base);
+                       }
+                       break;
+               }
+               num++;
+
+               if (!next)
+                       break;
+               str = next;
+       }
+       return num;
+}
+
+/**
+ * sscanf - Unformat a buffer into a list of arguments
+ * @buf:       input buffer
+ * @fmt:       formatting of buffer
+ * @...:       resulting arguments
+ */
+int sscanf(const char * buf, const char * fmt, ...)
+{
+       va_list args;
+       int i;
+
+       va_start(args,fmt);
+       i = vsscanf(buf,fmt,args);
+       va_end(args);
+       return i;
+}
+
+#endif
diff -r 092232fa1fbd extras/stubfw/startup.S
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/startup.S   Sat Nov 17 05:07:17 2007 +0100
@@ -0,0 +1,94 @@
+       .section .start,"ax"
+
+       .psr abi64
+       .psr lsb
+       .lsb
+
+       .globl _start
+       .proc _start
+_start:
+       /* IO-base.  */
+       movl r4=0x000000e0000000
+       ;;
+       mov ar.k0=r4
+       /* Init tpr.  */
+       mov cr.tpr=r0
+       /* Init RSE & stack. */
+       movl r2=0xff280000
+       mov ar.rsc=0    // lazy mode, 0 dirty bytes.
+       ;;
+       add r12=0x10000-16,r2
+       loadrs
+       ;;
+       movl r1=__gp
+       mov ar.bspstore=r2
+       ;;
+       srlz.d
+       movl r4=cmain
+       ;;
+       alloc   loc0=ar.pfs,0,1,4,0
+       mov out0=r8 // store
+       mov out1=r9 // console
+       mov out2=r10 // mem mb
+       mov out3=r11 // vcpu
+       //mov ar.rsc=3  // eager mode
+       ;;
+       bsw.1           // Use standard bank
+       ;;
+       movl r16=bss_start
+       movl r17=end
+       ;;
+       // Clear bss
+1:     cmp.ltu p6,p7=r16,r17
+       ;;
+       st8 [r16]=r0,8
+(p6)   br 1b
+       ;; 
+       mov  b1=r4
+       movl r5=pal_proc
+       ;;
+       mov  ar.k5=r5   // Pal entry point
+       br.call.sptk.many rp=b1
+       ;;
+       .endp _start
+
+       .text
+       
+       /* Pal.  */
+       .proc pal_proc
+pal_proc:
+       tbit.nz p7,p8=r28,8             /* 1-255 or 512-767: static conv (p8)*/
+       ;;
+       /* Xen always use the static convention.  */
+(p7)   mov r29=r33
+(p7)   mov r30=r34
+(p7)   mov r31=r35
+       ;;
+       break 0x110000
+       ;;
+(p7)   br.ret.sptk.few rp
+(p8)   br.cond.sptk.few rp
+       .endp pal_proc
+
+       .proc __hypercall
+       .globl __hypercall
+__hypercall:   
+       mov r2=r37
+       break 0x1000
+       br.ret.sptk.many b0
+       ;;
+       .endp __hypercall
+
+
+       .proc __hvmstub_hypercall
+       .globl __hvmstub_hypercall
+__hvmstub_hypercall:
+       mov r8=r32
+       mov r9=r33
+       mov r10=r34
+       mov r11=r35
+       mov r2=r36
+       break 0x1000
+       br.ret.sptk.many b0
+       ;;
+       .endp __hvmstub_hypercall
diff -r 092232fa1fbd extras/stubfw/string.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/string.c    Wed Nov 07 00:40:13 2007 +0100
@@ -0,0 +1,158 @@
+/* -*-  Mode:C; c-basic-offset:4; tab-width:4 -*-
+ ****************************************************************************
+ * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
+ ****************************************************************************
+ *
+ *        File: string.c
+ *      Author: Rolf Neugebauer (neugebar@xxxxxxxxxxxxx)
+ *     Changes: 
+ *              
+ *        Date: Aug 2003
+ * 
+ * Environment: Xen Minimal OS
+ * Description: Library function for string and memory manipulation
+ *              Origin unknown
+ *
+ ****************************************************************************
+ * $Id: c-insert.c,v 1.7 2002/11/08 16:04:34 rn Exp $
+ ****************************************************************************
+ */
+
+#if !defined HAVE_LIBC
+
+#include <os.h>
+#include <types.h>
+#include <lib.h>
+
+int memcmp(const void * cs,const void * ct,size_t count)
+{
+       const unsigned char *su1, *su2;
+       signed char res = 0;
+
+       for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+               if ((res = *su1 - *su2) != 0)
+                       break;
+       return res;
+}
+
+void * memcpy(void * dest,const void *src,size_t count)
+{
+       char *tmp = (char *) dest;
+    const char *s = src;
+
+       while (count--)
+               *tmp++ = *s++;
+
+       return dest;
+}
+
+int strncmp(const char * cs,const char * ct,size_t count)
+{
+       register signed char __res = 0;
+
+       while (count) {
+               if ((__res = *cs - *ct++) != 0 || !*cs++)
+                       break;
+               count--;
+       }
+
+       return __res;
+}
+
+int strcmp(const char * cs,const char * ct)
+{
+        register signed char __res;
+
+        while (1) {
+                if ((__res = *cs - *ct++) != 0 || !*cs++)
+                        break;
+        }
+
+        return __res;
+}
+
+char * strcpy(char * dest,const char *src)
+{
+        char *tmp = dest;
+
+        while ((*dest++ = *src++) != '\0')
+                /* nothing */;
+        return tmp;
+}
+
+char * strncpy(char * dest,const char *src,size_t count)
+{
+        char *tmp = dest;
+
+        while (count-- && (*dest++ = *src++) != '\0')
+                /* nothing */;
+
+        return tmp;
+}
+
+void * memset(void * s,int c,size_t count)
+{
+        char *xs = (char *) s;
+
+        while (count--)
+                *xs++ = c;
+
+        return s;
+}
+
+size_t strnlen(const char * s, size_t count)
+{
+        const char *sc;
+
+        for (sc = s; count-- && *sc != '\0'; ++sc)
+                /* nothing */;
+        return sc - s;
+}
+
+
+char * strcat(char * dest, const char * src)
+{
+    char *tmp = dest;
+    
+    while (*dest)
+        dest++;
+    
+    while ((*dest++ = *src++) != '\0');
+    
+    return tmp;
+}
+
+size_t strlen(const char * s)
+{
+       const char *sc;
+
+       for (sc = s; *sc != '\0'; ++sc)
+               /* nothing */;
+       return sc - s;
+}
+
+char * strchr(const char * s, int c)
+{
+        for(; *s != (char) c; ++s)
+                if (*s == '\0')
+                        return NULL;
+        return (char *)s;
+}
+
+char * strstr(const char * s1,const char * s2)
+{
+        int l1, l2;
+
+        l2 = strlen(s2);
+        if (!l2)
+                return (char *) s1;
+        l1 = strlen(s1);
+        while (l1 >= l2) {
+                l1--;
+                if (!memcmp(s1,s2,l2))
+                        return (char *) s1;
+                s1++;
+        }
+        return NULL;
+}
+#endif
diff -r 092232fa1fbd extras/stubfw/stubfw.lds
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/stubfw.lds  Sat Nov 17 05:10:41 2007 +0100
@@ -0,0 +1,49 @@
+OUTPUT_FORMAT("elf64-ia64-little")
+OUTPUT_ARCH(ia64)
+ENTRY(_start)
+SECTIONS
+{
+  . = 0xff800000;
+  .text :
+  {
+   *(.start)
+   *(.text)
+   *(.got)
+   *(.got.plt)
+   *(.rodata)
+   *(.rodata.*)
+   *(.opd)
+  }
+  .sdata :
+  {
+   *(.sdata)
+   *(.scommon)
+  }
+  .data : 
+  {
+   *(.data)
+   . = ALIGN(16,.);
+   bss_start = .;
+   *(.bss)
+   *(COMMON)
+   . = ALIGN(16,.);
+   end = .;
+  }
+  .pad :
+  {
+   . = 0xffa00000 - ABSOLUTE(.) - 1;
+   BYTE(0);
+  }
+
+
+  /DISCARD/ :
+  {
+    *(.rela.plabel)
+    *(.rela.reloc)
+    *(.rela.*)
+    *(.IA_64.unwind*)
+    *(.IA64.unwind*)
+    *(.modname)
+    *(.moddeps)
+  }
+}
diff -r 092232fa1fbd extras/stubfw/stubfw.map
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/stubfw.map  Thu Nov 22 04:45:39 2007 +0100
@@ -0,0 +1,548 @@
+
+Allocating common symbols
+Common symbol       size              file
+
+pci_mem_base        0x8               ioemu/pci.o
+serial1             0x8               main.o
+piix4_dev           0x8               ioemu/piix_pci.o
+bs_table            0x28              ioemu.o
+ioemu_trace         0x4               main.o
+piix3_dev           0x8               ioemu/piix_pci.o
+
+Discarded input sections
+
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 main.o
+ .IA_64.unwind  0x0000000000000000        0x0 main.o
+ .rela.start    0x0000000000000000        0x0 main.o
+ .rela.sdata    0x0000000000000000        0x0 main.o
+ .rela.text     0x0000000000000000        0x0 main.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 hobs.o
+ .IA_64.unwind  0x0000000000000000        0x0 hobs.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 events.o
+ .IA_64.unwind  0x0000000000000000        0x0 events.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 ioemu/serial.o
+ .IA_64.unwind  0x0000000000000000        0x0 ioemu/serial.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 ioemu/mc146818rtc.o
+ .IA_64.unwind  0x0000000000000000        0x0 ioemu/mc146818rtc.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 ioemu/pci.o
+ .IA_64.unwind  0x0000000000000000        0x0 ioemu/pci.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 ioemu/irq.o
+ .IA_64.unwind  0x0000000000000000        0x0 ioemu/irq.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 ioemu/piix_pci.o
+ .IA_64.unwind  0x0000000000000000        0x0 ioemu/piix_pci.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 ioemu/ide.o
+ .IA_64.unwind  0x0000000000000000        0x0 ioemu/ide.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 ioemu/cdrom.o
+ .IA_64.unwind  0x0000000000000000        0x0 ioemu/cdrom.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 ioemu/block.o
+ .IA_64.unwind  0x0000000000000000        0x0 ioemu/block.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 ioemu/vl.o
+ .IA_64.unwind  0x0000000000000000        0x0 ioemu/vl.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 ioemu.o
+ .IA_64.unwind  0x0000000000000000        0x0 ioemu.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 console.o
+ .IA_64.unwind  0x0000000000000000        0x0 console.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 xenbus.o
+ .IA_64.unwind  0x0000000000000000        0x0 xenbus.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 xenbus_test.o
+ .IA_64.unwind  0x0000000000000000        0x0 xenbus_test.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 gnttab.o
+ .IA_64.unwind  0x0000000000000000        0x0 gnttab.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 vbd.o
+ .IA_64.unwind  0x0000000000000000        0x0 vbd.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 block-vbd.o
+ .IA_64.unwind  0x0000000000000000        0x0 block-vbd.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 printf.o
+ .IA_64.unwind  0x0000000000000000        0x0 printf.o
+ .IA_64.unwind_info
+                0x0000000000000000        0x0 string.o
+ .IA_64.unwind  0x0000000000000000        0x0 string.o
+
+Memory Configuration
+
+Name             Origin             Length             Attributes
+*default*        0x0000000000000000 0xffffffffffffffff
+
+Linker script and memory map
+
+                0x00000000ff800000                . = 0xff800000
+
+.text           0x00000000ff800000    0x1e9e0
+ *(.start)
+ .start         0x00000000ff800000      0x120 startup.o
+                0x00000000ff800000                _start
+ *(.text)
+ .text          0x00000000ff800120      0xbe0 main.o
+                0x00000000ff8008f0                cmain
+                0x00000000ff8002b0                dump_shared_info
+                0x00000000ff800420                ia64_callback
+                0x00000000ff800240                exit
+                0x00000000ff800120                setup_shared_info
+ .text          0x00000000ff800d00       0x70 startup.o
+                0x00000000ff800d40                __hvmstub_hypercall
+                0x00000000ff800d30                __hypercall
+ .text          0x00000000ff800d70      0x500 hobs.o
+                0x00000000ff801190                build_hob
+ .text          0x00000000ff801270      0xe90 events.o
+                0x00000000ff8018f0                bind_virq
+                0x00000000ff801a50                init_events
+                0x00000000ff8015b0                bind_evtchn
+                0x00000000ff801270                unbind_all_ports
+                0x00000000ff8017f0                unbind_evtchn
+                0x00000000ff801b70                evtchn_alloc_unbound
+                0x00000000ff802020                poll_evtchn
+                0x00000000ff801c50                evtchn_bind_interdomain
+                0x00000000ff801e00                do_hypervisor_callback
+ .text          0x00000000ff802100      0xa50 ioemu/serial.o
+                0x00000000ff802980                serial_event
+                0x00000000ff8027e0                serial_can_receive
+                0x00000000ff802930                serial_receive1
+                0x00000000ff8028e0                serial_can_receive1
+                0x00000000ff8029f0                serial_init
+                0x00000000ff802800                serial_receive_byte
+ .text          0x00000000ff802b50      0x450 ioemu/mc146818rtc.o
+                0x00000000ff802e80                rtc_init
+                0x00000000ff802e50                rtc_set_memory
+                0x00000000ff802cc0                cmos_ioport_read
+                0x00000000ff802b50                cmos_ioport_write
+ .text          0x00000000ff802fa0     0x1620 ioemu/pci.o
+                0x00000000ff803b80                pci_data_write
+                0x00000000ff803330                pci_register_io_region
+                0x00000000ff802fa0                pci_register_bus
+                0x00000000ff803720                pci_default_read_config
+                0x00000000ff8037f0                pci_default_write_config
+                0x00000000ff8030f0                pci_bus_num
+                0x00000000ff804570                pci_info
+                0x00000000ff804420                pci_for_each_device
+                0x00000000ff8033d0                pci_to_cpu_addr
+                0x00000000ff803100                pci_register_device
+                0x00000000ff803040                pci_register_secondary_bus
+                0x00000000ff803cc0                pci_data_read
+ .text          0x00000000ff8045c0      0x2c0 ioemu/irq.o
+                0x00000000ff804820                qemu_irq_invert
+                0x00000000ff8045c0                qemu_set_irq
+                0x00000000ff8046a0                qemu_allocate_irqs
+ .text          0x00000000ff804880      0xfa0 ioemu/piix_pci.o
+                0x00000000ff805620                piix3_init
+                0x00000000ff805510                piix_init
+                0x00000000ff805720                piix4_init
+                0x00000000ff804c90                i440fx_init
+ .text          0x00000000ff805820     0x9070 ioemu/ide.o
+                0x00000000ff80dff0                pci_cmd646_ide_init
+                0x00000000ff80e620                pci_piix4_ide_init
+                0x00000000ff80e3c0                pci_piix3_ide_init
+ .text          0x00000000ff80e890      0x770 ioemu/cdrom.o
+                0x00000000ff80ea10                cdrom_read_toc
+                0x00000000ff80ec80                cdrom_read_toc_raw
+ .text          0x00000000ff80f000     0x12c0 ioemu/block.o
+                0x00000000ff80f960                bdrv_get_type_hint
+                0x00000000ff80f8b0                bdrv_set_type_hint
+                0x00000000ff80f9e0                bdrv_set_change_cb
+                0x00000000ff80fad0                bdrv_aio_read
+                0x00000000ff80fff0                bdrv_media_changed
+                0x00000000ff80f1a0                bdrv_close
+                0x00000000ff80f000                bdrv_register
+                0x00000000ff810210                bdrv_set_locked
+                0x00000000ff80fa00                bdrv_flush
+                0x00000000ff80f080                bdrv_new
+                0x00000000ff80f880                bdrv_set_geometry_hint
+                0x00000000ff80f270                bdrv_read
+                0x00000000ff80f4b0                bdrv_write
+                0x00000000ff80f980                bdrv_get_translation_hint
+                0x00000000ff80f690                bdrv_getlength
+                0x00000000ff80f9c0                bdrv_is_read_only
+                0x00000000ff8100d0                bdrv_eject
+                0x00000000ff80ff20                bdrv_is_inserted
+                0x00000000ff80f7d0                bdrv_set_boot_sector
+                0x00000000ff80f8f0                bdrv_set_translation_hint
+                0x00000000ff80fd70                bdrv_aio_cancel
+                0x00000000ff80f760                bdrv_get_geometry
+                0x00000000ff80fc20                bdrv_aio_write
+                0x00000000ff80f9a0                bdrv_is_removable
+                0x00000000ff8101f0                bdrv_is_locked
+                0x00000000ff80f910                bdrv_get_geometry_hint
+ .text          0x00000000ff8102c0      0x520 ioemu/vl.o
+                0x00000000ff810350                qemu_chr_reset
+                0x00000000ff810360                qemu_chr_write
+                0x00000000ff8102c0                qemu_chr_event
+                0x00000000ff8103d0                qemu_chr_ioctl
+                0x00000000ff8105b0                qemu_chr_printf
+                0x00000000ff810530                qemu_chr_read
+                0x00000000ff810480                qemu_chr_can_read
+                0x00000000ff810680                qemu_chr_send_event
+                0x00000000ff810710                qemu_chr_add_handlers
+ .text          0x00000000ff8107e0     0x1720 ioemu.o
+                0x00000000ff810ec0                default_ioport_readb
+                0x00000000ff8107e0                pstrcpy
+                0x00000000ff811c10                cpu_physical_memory_rw
+                0x00000000ff811890                cpu_outl
+                0x00000000ff811510                register_ioport_write
+                0x00000000ff810fe0                default_ioport_readw
+                0x00000000ff8116f0                cpu_outb
+                0x00000000ff811ae0                cpu_inl
+                0x00000000ff8108d0                hw_error
+                0x00000000ff811170                default_ioport_writel
+                0x00000000ff811060                default_ioport_writew
+                0x00000000ff8117c0                cpu_outw
+                0x00000000ff811200                init_ioports
+                0x00000000ff810f50                default_ioport_writeb
+                0x00000000ff8110e0                default_ioport_readl
+                0x00000000ff810860                qemu_mallocz
+                0x00000000ff811a20                cpu_inw
+                0x00000000ff811960                cpu_inb
+                0x00000000ff811eb0                init_iosapic
+                0x00000000ff811330                register_ioport_read
+ .text          0x00000000ff811f00     0x14e0 console.o
+                0x00000000ff813350                term_printf
+                0x00000000ff8132b0                printf
+                0x00000000ff812fd0                qemu_chr_open_xc
+                0x00000000ff8120e0                xencons_wait_send
+                0x00000000ff812010                xencons_ring_send
+                0x00000000ff8130a0                vprintf
+                0x00000000ff811f00                xencons_ring_send_no_notify
+                0x00000000ff813220                printk
+                0x00000000ff812190                xencons_input
+                0x00000000ff8123d0                init_console
+ .text          0x00000000ff8133e0     0x1c30 xenbus.o
+                0x00000000ff8142c0                xenbus_debug_msg
+                0x00000000ff8145c0                xenbus_read
+                0x00000000ff814960                xenbus_rm
+                0x00000000ff8133e0                xenbus_allocate_req
+                0x00000000ff813a70                init_xenbus
+                0x00000000ff814de0                xenbus_transaction_end
+                0x00000000ff813b60                xenbus_wait_for_value
+                0x00000000ff8143c0                xenbus_ls
+                0x00000000ff814820                xenbus_watch_path
+                0x00000000ff814b60                xenbus_set_perms
+                0x00000000ff8146d0                xenbus_write
+                0x00000000ff814cf0                xenbus_transaction_start
+                0x00000000ff814f30                xenbus_read_integer
+                0x00000000ff814a50                xenbus_get_perms
+ .text          0x00000000ff815010      0x6f0 xenbus_test.o
+                0x00000000ff815440                test_xenbus
+ .text          0x00000000ff815700      0x950 gnttab.o
+                0x00000000ff815a30                gnttab_end_transfer
+                0x00000000ff815d60                gnttabop_error
+                0x00000000ff815780                gnttab_grant_access
+                0x00000000ff815db0                init_gnttab
+                0x00000000ff815c30                alloc_pages
+                0x00000000ff815930                gnttab_end_access
+                0x00000000ff815ce0                gnttab_alloc_and_grant
+                0x00000000ff815870                gnttab_grant_transfer
+ .text          0x00000000ff816050     0x17f0 vbd.o
+                0x00000000ff816a10                init_vbd
+                0x00000000ff816050                xenbus_printf
+                0x00000000ff8175e0                vbd_test
+                0x00000000ff816130                xenbus_scanf
+                0x00000000ff8170b0                vbd_request
+ .text          0x00000000ff817840      0x610 block-vbd.o
+                0x00000000ff817e00                bdrv_init
+                0x00000000ff817c60                bdrv_open_vbd
+ *fill*         0x00000000ff817e50       0x10 00
+ .text          0x00000000ff817e60      0x420 event-asm.o
+                0x00000000ff817e60                callback_entry
+ .text          0x00000000ff818280     0x2a30 printf.o
+                0x00000000ff819af0                vsprintf
+                0x00000000ff818730                simple_strtoll
+                0x00000000ff819a60                snprintf
+                0x00000000ff818450                simple_strtol
+                0x00000000ff819be0                vsscanf
+                0x00000000ff818f10                vsnprintf
+                0x00000000ff81ac20                sscanf
+                0x00000000ff819b50                sprintf
+                0x00000000ff818280                simple_strtoul
+                0x00000000ff818500                simple_strtoull
+ .text          0x00000000ff81acb0      0x500 string.o
+                0x00000000ff81ae20                strcpy
+                0x00000000ff81ad10                memcpy
+                0x00000000ff81aee0                strnlen
+                0x00000000ff81af70                strcat
+                0x00000000ff81b0a0                strstr
+                0x00000000ff81ad50                strncmp
+                0x00000000ff81ae50                strncpy
+                0x00000000ff81acb0                memcmp
+                0x00000000ff81aea0                memset
+                0x00000000ff81add0                strcmp
+                0x00000000ff81afd0                strlen
+                0x00000000ff81b020                strchr
+ *fill*         0x00000000ff81b1b0       0x10 00
+ .text          0x00000000ff81b1c0      0x120 __umoddi3.o
+                0x00000000ff81b1c0                __umoddi3
+ .text          0x00000000ff81b2e0      0x110 __divdi3.o
+                0x00000000ff81b2e0                __divdi3
+ *fill*         0x00000000ff81b3f0       0x10 00
+ .text          0x00000000ff81b400      0x110 __udivdi3.o
+                0x00000000ff81b400                __udivdi3
+ *fill*         0x00000000ff81b510       0x10 00
+ .text          0x00000000ff81b520       0xe0 __udivsi3.o
+                0x00000000ff81b520                __udivsi3
+ .text          0x00000000ff81b600       0xf0 __umodsi3.o
+                0x00000000ff81b600                __umodsi3
+ *(.got)
+ .got           0x00000000ff81b6f0      0x220 main.o
+ *(.got.plt)
+ .got.plt       0x00000000ff81b910        0x0 main.o
+                0x00000000ff81b910                _GLOBAL_OFFSET_TABLE_
+ *(.rodata)
+ .rodata        0x00000000ff81b910       0x78 main.o
+ .rodata        0x00000000ff81b988       0x1a events.o
+ *fill*         0x00000000ff81b9a2        0x6 00
+ .rodata        0x00000000ff81b9a8       0x80 ioemu/serial.o
+ .rodata        0x00000000ff81ba28       0xd8 ioemu/mc146818rtc.o
+ .rodata        0x00000000ff81bb00      0x3e0 ioemu/pci.o
+ .rodata        0x00000000ff81bee0      0x850 ioemu/ide.o
+ .rodata        0x00000000ff81c730       0x1a ioemu.o
+ *fill*         0x00000000ff81c74a        0x6 00
+ .rodata        0x00000000ff81c750      0x238 console.o
+ .rodata        0x00000000ff81c988       0x1a xenbus.o
+ *fill*         0x00000000ff81c9a2        0x6 00
+ .rodata        0x00000000ff81c9a8       0x1a xenbus_test.o
+ *fill*         0x00000000ff81c9c2        0x6 00
+ .rodata        0x00000000ff81c9c8       0xa8 gnttab.o
+ .rodata        0x00000000ff81ca70       0x1a vbd.o
+ *fill*         0x00000000ff81ca8a        0x6 00
+ .rodata        0x00000000ff81ca90      0x780 printf.o
+ .rodata        0x00000000ff81d210       0x1a string.o
+ *(.rodata.*)
+ *fill*         0x00000000ff81d22a        0x6 00
+ .rodata.str1.8
+                0x00000000ff81d230      0x194 main.o
+ *fill*         0x00000000ff81d3c4        0x4 00
+ .rodata.str1.8
+                0x00000000ff81d3c8       0xcc events.o
+ *fill*         0x00000000ff81d494        0x4 00
+ .rodata.str1.8
+                0x00000000ff81d498      0x34b ioemu/pci.o
+ *fill*         0x00000000ff81d7e3        0x5 00
+ .rodata.str1.8
+                0x00000000ff81d7e8       0x22 ioemu/irq.o
+ *fill*         0x00000000ff81d80a        0x6 00
+ .rodata.str1.8
+                0x00000000ff81d810       0x36 ioemu/piix_pci.o
+ *fill*         0x00000000ff81d846        0x2 00
+ .rodata.str1.8
+                0x00000000ff81d848       0x72 ioemu/ide.o
+ *fill*         0x00000000ff81d8ba        0x6 00
+ .rodata.str1.8
+                0x00000000ff81d8c0       0x21 ioemu/block.o
+ *fill*         0x00000000ff81d8e1        0x7 00
+ .rodata.str1.8
+                0x00000000ff81d8e8      0x1cb ioemu.o
+                                        0x1d3 (size before relaxing)
+ *fill*         0x00000000ff81dab3        0x5 00
+ .rodata.str1.8
+                0x00000000ff81dab8      0x18c console.o
+                                        0x192 (size before relaxing)
+ *fill*         0x00000000ff81dc44        0x4 00
+ .rodata.str1.8
+                0x00000000ff81dc48      0x173 xenbus.o
+                                        0x193 (size before relaxing)
+ *fill*         0x00000000ff81ddbb        0x5 00
+ .rodata.str1.8
+                0x00000000ff81ddc0      0x1e3 xenbus_test.o
+                                        0x25b (size before relaxing)
+ *fill*         0x00000000ff81dfa3        0x5 00
+ .rodata.str1.8
+                0x00000000ff81dfa8      0x1cc gnttab.o
+ *fill*         0x00000000ff81e174        0x4 00
+ .rodata.str1.8
+                0x00000000ff81e178      0x2be vbd.o
+                                        0x2fe (size before relaxing)
+ *fill*         0x00000000ff81e436        0x2 00
+ .rodata.str1.8
+                0x00000000ff81e438       0xc7 block-vbd.o
+ *fill*         0x00000000ff81e4ff        0x1 00
+ .rodata.str1.8
+                0x00000000ff81e500       0x58 printf.o
+                                         0x57 (size before relaxing)
+ *(.opd)
+ *fill*         0x00000000ff81e558        0x8 00
+ .opd           0x00000000ff81e560      0x480 main.o
+
+.sdata          0x00000000ff81e9e0       0x58
+ *(.sdata)
+ .sdata         0x00000000ff81e9e0        0x8 main.o
+                0x00000000ff81e9e0                shared_info
+ .sdata         0x00000000ff81e9e8        0x4 ioemu/ide.o
+ *fill*         0x00000000ff81e9ec        0x4 00
+ .sdata         0x00000000ff81e9f0        0x8 ioemu.o
+ .sdata         0x00000000ff81e9f8        0x4 console.o
+ *fill*         0x00000000ff81e9fc        0x4 00
+ .sdata         0x00000000ff81ea00        0x8 gnttab.o
+ .sdata         0x00000000ff81ea08        0x8 vbd.o
+ *(.scommon)
+ .scommon       0x00000000ff81ea10        0xc main.o
+                0x00000000ff81ea10                serial1
+                0x00000000ff81ea18                ioemu_trace
+ *fill*         0x00000000ff81ea1c        0x4 00
+ .scommon       0x00000000ff81ea20        0x8 ioemu/pci.o
+                0x00000000ff81ea20                pci_mem_base
+ .scommon       0x00000000ff81ea28       0x10 ioemu/piix_pci.o
+                0x00000000ff81ea28                piix4_dev
+                0x00000000ff81ea30                piix3_dev
+
+.sbss           0x00000000ff81ea38       0x80
+ .sbss          0x00000000ff81ea38       0x28 main.o
+ .sbss          0x00000000ff81ea60       0x10 ioemu/pci.o
+ .sbss          0x00000000ff81ea70        0x8 ioemu/block.o
+ .sbss          0x00000000ff81ea78        0x8 ioemu.o
+ .sbss          0x00000000ff81ea80       0x14 console.o
+ *fill*         0x00000000ff81ea94        0x4 00
+ .sbss          0x00000000ff81ea98       0x10 xenbus.o
+ .sbss          0x00000000ff81eaa8        0x8 gnttab.o
+ .sbss          0x00000000ff81eab0        0x8 vbd.o
+
+.data           0x00000000ff81eab8     0xb6f0
+ *(.data)
+ .data          0x00000000ff81eab8        0x0 main.o
+ .data          0x00000000ff81eab8        0x0 startup.o
+ .data          0x00000000ff81eab8        0x0 hobs.o
+ .data          0x00000000ff81eab8        0x0 events.o
+ .data          0x00000000ff81eab8        0x0 ioemu/serial.o
+ .data          0x00000000ff81eab8        0x0 ioemu/mc146818rtc.o
+ .data          0x00000000ff81eab8      0x240 ioemu/pci.o
+ .data          0x00000000ff81ecf8        0x0 ioemu/irq.o
+ .data          0x00000000ff81ecf8        0x0 ioemu/piix_pci.o
+ .data          0x00000000ff81ecf8        0x0 ioemu/ide.o
+ .data          0x00000000ff81ecf8        0x0 ioemu/cdrom.o
+ .data          0x00000000ff81ecf8        0x0 ioemu/block.o
+ .data          0x00000000ff81ecf8        0x0 ioemu/vl.o
+ .data          0x00000000ff81ecf8        0x0 ioemu.o
+ .data          0x00000000ff81ecf8       0x40 console.o
+ .data          0x00000000ff81ed38       0xe0 xenbus.o
+ .data          0x00000000ff81ee18       0xe0 xenbus_test.o
+ .data          0x00000000ff81eef8        0x0 gnttab.o
+ .data          0x00000000ff81eef8        0x0 vbd.o
+ .data          0x00000000ff81eef8      0x108 block-vbd.o
+                0x00000000ff81eef8                bdrv_vbd
+ .data          0x00000000ff81f000        0x0 event-asm.o
+ .data          0x00000000ff81f000      0x100 printf.o
+                0x00000000ff81f000                _ctype
+ .data          0x00000000ff81f100        0x0 string.o
+ .data          0x00000000ff81f100        0x0 __umoddi3.o
+ .data          0x00000000ff81f100        0x0 __divdi3.o
+ .data          0x00000000ff81f100        0x0 __udivdi3.o
+ .data          0x00000000ff81f100        0x0 __udivsi3.o
+ .data          0x00000000ff81f100        0x0 __umodsi3.o
+                0x00000000ff81f100                . = (0x10 ALIGN .)
+                0x00000000ff81f100                bss_start = .
+ *(.bss)
+ .bss           0x00000000ff81f100        0x0 main.o
+ .bss           0x00000000ff81f100        0x0 startup.o
+ .bss           0x00000000ff81f100        0x0 hobs.o
+ .bss           0x00000000ff81f100     0x6080 events.o
+ .bss           0x00000000ff825180        0x0 ioemu/serial.o
+ .bss           0x00000000ff825180        0x0 ioemu/mc146818rtc.o
+ .bss           0x00000000ff825180        0x0 ioemu/pci.o
+ .bss           0x00000000ff825180        0x0 ioemu/irq.o
+ .bss           0x00000000ff825180       0x10 ioemu/piix_pci.o
+ .bss           0x00000000ff825190        0x0 ioemu/ide.o
+ .bss           0x00000000ff825190        0x0 ioemu/cdrom.o
+ .bss           0x00000000ff825190        0x0 ioemu/block.o
+ .bss           0x00000000ff825190        0x0 ioemu/vl.o
+ .bss           0x00000000ff825190     0x1c90 ioemu.o
+ .bss           0x00000000ff826e20      0x4e0 console.o
+ .bss           0x00000000ff827300      0x500 xenbus.o
+ .bss           0x00000000ff827800        0x0 xenbus_test.o
+ .bss           0x00000000ff827800     0x2000 gnttab.o
+ .bss           0x00000000ff829800      0x980 vbd.o
+ .bss           0x00000000ff82a180        0x0 block-vbd.o
+ .bss           0x00000000ff82a180        0x0 event-asm.o
+ .bss           0x00000000ff82a180        0x0 printf.o
+ .bss           0x00000000ff82a180        0x0 string.o
+ .bss           0x00000000ff82a180        0x0 __umoddi3.o
+ .bss           0x00000000ff82a180        0x0 __divdi3.o
+ .bss           0x00000000ff82a180        0x0 __udivdi3.o
+ .bss           0x00000000ff82a180        0x0 __udivsi3.o
+ .bss           0x00000000ff82a180        0x0 __umodsi3.o
+ *(COMMON)
+ COMMON         0x00000000ff82a180       0x28 ioemu.o
+                0x00000000ff82a180                bs_table
+                0x00000000ff82a1a8                . = (0x10 ALIGN .)
+                0x00000000ff82a1a8                end = .
+
+.pad            0x00000000ff82a1a8   0x1d5e58
+                0x00000000ff9fffff                . = ((0xffa00000 - <code 
342> (.)) - 0x1)
+ *fill*         0x00000000ff82a1a8   0x1d5e57 00
+                0x00000000ff9fffff        0x1 BYTE 0x0
+
+/DISCARD/
+ *(.rela.plabel)
+ *(.rela.reloc)
+ *(.rela.*)
+ *(.IA_64.unwind*)
+ *(.IA64.unwind*)
+ *(.modname)
+ *(.moddeps)
+LOAD main.o
+LOAD startup.o
+LOAD hobs.o
+LOAD events.o
+LOAD ioemu/serial.o
+LOAD ioemu/mc146818rtc.o
+LOAD ioemu/pci.o
+LOAD ioemu/irq.o
+LOAD ioemu/piix_pci.o
+LOAD ioemu/ide.o
+LOAD ioemu/cdrom.o
+LOAD ioemu/block.o
+LOAD ioemu/vl.o
+LOAD ioemu.o
+LOAD console.o
+LOAD xenbus.o
+LOAD xenbus_test.o
+LOAD gnttab.o
+LOAD vbd.o
+LOAD block-vbd.o
+LOAD event-asm.o
+LOAD printf.o
+LOAD string.o
+LOAD __umoddi3.o
+LOAD __divdi3.o
+LOAD __udivdi3.o
+LOAD __udivsi3.o
+LOAD __umodsi3.o
+OUTPUT(stubfw.elf elf64-ia64-little)
+
+.comment        0x0000000000000000      0x31e
+ .comment       0x0000000000000000       0x26 main.o
+ .comment       0x0000000000000026       0x26 hobs.o
+ .comment       0x000000000000004c       0x26 events.o
+ .comment       0x0000000000000072       0x26 ioemu/serial.o
+ .comment       0x0000000000000098       0x26 ioemu/mc146818rtc.o
+ .comment       0x00000000000000be       0x26 ioemu/pci.o
+ .comment       0x00000000000000e4       0x26 ioemu/irq.o
+ .comment       0x000000000000010a       0x26 ioemu/piix_pci.o
+ .comment       0x0000000000000130       0x26 ioemu/ide.o
+ .comment       0x0000000000000156       0x26 ioemu/cdrom.o
+ .comment       0x000000000000017c       0x26 ioemu/block.o
+ .comment       0x00000000000001a2       0x26 ioemu/vl.o
+ .comment       0x00000000000001c8       0x26 ioemu.o
+ .comment       0x00000000000001ee       0x26 console.o
+ .comment       0x0000000000000214       0x26 xenbus.o
+ .comment       0x000000000000023a       0x26 xenbus_test.o
+ .comment       0x0000000000000260       0x26 gnttab.o
+ .comment       0x0000000000000286       0x26 vbd.o
+ .comment       0x00000000000002ac       0x26 block-vbd.o
+ .comment       0x00000000000002d2       0x26 printf.o
+ .comment       0x00000000000002f8       0x26 string.o
diff -r 092232fa1fbd extras/stubfw/stubfw.mk
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/stubfw.mk   Fri Nov 16 03:48:09 2007 +0100
@@ -0,0 +1,59 @@
+#
+# The file contains the common make rules for building mini-os.
+#
+
+#debug = y
+
+# Define some default flags.
+# NB. '-Wcast-qual' is nasty, so I omitted it.
+DEF_CFLAGS := -fno-builtin -Wall -Werror -Wredundant-decls -Wno-format
+DEF_CFLAGS += -Wstrict-prototypes -Wnested-externs -Wpointer-arith #-Winline
+DEF_CFLAGS += -D__XEN_INTERFACE_VERSION__=$(XEN_INTERFACE_VERSION)
+#DEF_CFLAGS += -nostdinc
+
+DEF_ASFLAGS = -D__ASSEMBLY__
+DEF_LDFLAGS =
+
+ifeq ($(debug),y)
+DEF_CFLAGS += -g
+else
+DEF_CFLAGS += -O
+endif
+
+# Build the CFLAGS and ASFLAGS for compiling and assembling.
+# DEF_... flags are the common mini-os flags,
+# ARCH_... flags may be defined in arch/$(TARGET_ARCH_FAM/rules.mk
+CFLAGS := $(DEF_CFLAGS) $(ARCH_CFLAGS)
+ASFLAGS := $(DEF_ASFLAGS) $(ARCH_ASFLAGS)
+LDFLAGS := $(DEF_LDFLAGS) $(ARCH_LDFLAGS)
+
+# The path pointing to the architecture specific header files.
+ARCH_INC := $(STUBFW_ROOT)/include/$(TARGET_ARCH_FAM)
+
+# Special build dependencies.
+# Rebuild all after touching this/these file(s)
+EXTRA_DEPS = $(STUBFW_ROOT)/stubfw.mk 
+
+# Find all header files for checking dependencies.
+HDRS := $(wildcard $(STUBFW_ROOT)/include/*.h)
+HDRS += $(wildcard $(STUBFW_ROOT)/*.h)
+HDRS += $(wildcard $(STUBFW_ROOT)/include/xen/*.h)
+HDRS += $(wildcard $(ARCH_INC)/*.h)
+# For special wanted header directories.
+extra_heads := $(foreach dir,$(EXTRA_INC),$(wildcard $(dir)/*.h))
+HDRS += $(extra_heads)
+
+# Add the special header directories to the include paths.
+#extra_incl := $(foreach dir,$(EXTRA_INC),-I$(STUBFW_ROOT)/include/$(dir))
+override CPPFLAGS := -I$(STUBFW_ROOT)/include $(CPPFLAGS) -I$(ARCH_INC) 
$(extra_incl)
+
+
+%.o: %.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
+
+%.o: %.S
+       $(CC) $(ASFLAGS) $(CPPFLAGS) -c $< -o $@
+
+
+
+
diff -r 092232fa1fbd extras/stubfw/vbd.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/vbd.c       Wed Nov 21 03:26:48 2007 +0100
@@ -0,0 +1,409 @@
+#include "os.h"
+#include "xenbus.h"
+#include "events.h"
+#include "errno.h"
+#include <xen/io/blkif.h>
+#include <xen/io/protocols.h>
+#include <xen/io/xenbus.h>
+#include "gnttab.h"
+#include "vbd.h"
+#include "ioemu/vl.h"
+
+const char*
+xenbus_printf(struct xenbus_req *req,
+             xenbus_transaction_t xbt,
+             const char* node, const char* path,
+             const char* fmt, ...)
+{
+    va_list args;
+    char fullpath[256];
+    char val[256];
+
+    sprintf(fullpath,"%s/%s",node,path);
+    va_start(args, fmt);
+    vsprintf(val,fmt,args);
+    va_end(args);
+    return xenbus_write(req, xbt, fullpath, val);
+}
+
+const char*
+xenbus_scanf(struct xenbus_req *req,
+            xenbus_transaction_t xbt,
+             const char* node, const char* path,
+             const char* fmt, ...)
+{
+    va_list args;
+    const char *msg;
+    char *res;
+    char fullpath[256];
+
+    sprintf(fullpath,"%s/%s",node,path);
+    msg = xenbus_read(req, xbt, fullpath, &res);
+    if (msg)
+      return msg;
+    
+    va_start(args, fmt);
+    vsscanf(res,fmt,args);
+    va_end(args);
+
+    return NULL;
+}
+
+
+#define MAX_VBD 4
+
+static struct vbd_info vbds[MAX_VBD];
+static struct xenbus_req *vbd_req;
+static char vbd_req_buf[1024];
+
+static void vbd_handler (evtchn_port_t port, void *data)
+{
+  //printk ("vbd_handler\n");
+}
+
+static int setup_blkring(struct vbd_info *info)
+{
+       blkif_sring_t *sring;
+       //int err;
+
+       info->ring_ref = GRANT_INVALID_REF;
+       info->otherend_id = 0; //FIXME
+
+       sring = (blkif_sring_t *)alloc_pages (1);
+       if (!sring) {
+         //xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
+               return -ENOMEM;
+       }
+       SHARED_RING_INIT(sring);
+       FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
+
+       info->ring_ref = gnttab_grant_access (info->otherend_id,
+                                             addr_to_mfn(info->ring.sring),
+                                             0);
+       if (info->ring_ref == GRANT_INVALID_REF)
+         goto fail;
+
+       if (evtchn_alloc_unbound (info->otherend_id, vbd_handler, info,
+                                 &info->evtchn) != 0)
+         goto fail;
+       return 0;
+ fail:
+       // FIXME: free blk
+       return -1;
+}
+
+/* Common code used when first setting up, and when resuming. */
+static int
+talk_to_backend(struct vbd_info *info)
+{
+       xenbus_transaction_t xbt;
+       const char *msg;
+       int retry;
+
+again:
+       msg = xenbus_transaction_start(vbd_req, &xbt);
+       if (msg) {
+         //xenbus_dev_fatal(dev, err, "starting transaction");
+               goto destroy_blkring;
+       }
+
+       msg = xenbus_printf(vbd_req, xbt, info->node_name,
+                           "ring-ref", "%u", info->ring_ref);
+       if (msg) {
+         //message = "writing ring-ref";
+               goto abort_transaction;
+       }
+       msg = xenbus_printf(vbd_req, xbt, info->node_name,
+                           "event-channel", "%u", info->evtchn);
+       if (msg) {
+         //message = "writing event-channel";
+               goto abort_transaction;
+       }
+       msg = xenbus_printf(vbd_req, xbt, info->node_name, "protocol", "%s",
+                           XEN_IO_PROTO_ABI_NATIVE);
+       if (msg) {
+         //message = "writing protocol";
+               goto abort_transaction;
+       }
+
+       msg = xenbus_transaction_end(vbd_req, xbt, 0, &retry);
+       if (msg) {
+         if (retry)
+           goto again;
+         //xenbus_dev_fatal(dev, err, "completing transaction");
+         goto destroy_blkring;
+       }
+
+       msg = xenbus_printf(vbd_req, XBT_NIL, info->node_name,
+                           "state", "%u", XenbusStateConnected);
+       if (msg)
+         printk ("vbd: cannot switch state: %s\n", msg);
+       return 0;
+
+ abort_transaction:
+       printk ("vbd: abort transaction: %s\n", msg);
+       xenbus_transaction_end(vbd_req, xbt, 1, &retry);
+       //if (message)
+       //xenbus_dev_fatal(dev, err, "%s", message);
+ destroy_blkring:
+       //blkif_free(info, 0);
+       // out:
+       return -1;
+}
+
+static int
+find_backend (struct vbd_info *info)
+{
+      const char *msg;
+      char *res;
+      snprintf (info->backend, sizeof (info->backend),
+               "%s/%s", info->node_name, "backend");
+      msg = xenbus_read(vbd_req, XBT_NIL, info->backend,
+                       &res);
+      if (msg)
+       return -1;
+      pstrcpy (info->backend, sizeof (info->backend), res);
+      return 0;
+}
+
+static int
+wait_backend (struct vbd_info *info)
+{
+    char path[256];
+    sprintf(path,"%s/state",info->backend);
+
+    xenbus_watch_path(vbd_req, XBT_NIL, path);
+
+    if (xenbus_wait_for_value(vbd_req, path, "4") == NULL)
+      return 0;
+    else
+      return -1;
+}
+
+static int
+vbd_connect (struct vbd_info *info)
+{
+  const char *msg;
+  unsigned int binfo;
+
+  msg = xenbus_scanf (vbd_req, XBT_NIL, info->backend, "sectors", "%Lu",
+                     &info->sectors);
+  if (msg)
+    return -1;
+  msg = xenbus_scanf (vbd_req, XBT_NIL, info->backend, "info", "%u",
+                     &binfo);
+  if (msg)
+    return -1;
+  msg = xenbus_scanf (vbd_req, XBT_NIL, info->backend, "sector-size", "%lu",
+                     &info->sector_size);
+  if (msg)
+    return -1;
+  printk ("%s: %lu sectors (%lu bytes), info=%u\n",
+         info->node_name, info->sectors, info->sector_size, binfo);
+  info->is_ro = (binfo & VDISK_READONLY) ? 1 : 0;
+  return 0;
+}
+
+void init_vbd(void)
+{
+    char *dirs[MAX_VBD];
+    int nbr_entries;
+    const char* msg;
+    int i;
+
+    vbd_req = xenbus_allocate_req (vbd_req_buf, sizeof (vbd_req_buf));
+    nbr_entries = ARRAY_SIZE(dirs);
+    msg = xenbus_ls (vbd_req, XBT_NIL, "device/vbd", dirs, &nbr_entries);
+    if (msg != NULL) {
+      printk ("can't list vbd: %s\n", msg);
+      return;
+    }
+    if (nbr_entries == 0) {
+      printk ("no vbd devices\n");
+      return;
+    }
+    if (nbr_entries > MAX_VBD)
+      nbr_entries = MAX_VBD;
+    printk ("VBD:");
+    for (i = 0; i < nbr_entries; i++)
+      printk (" %s", dirs[i]);
+    printk ("\n");
+
+    for (i = 0; i < nbr_entries; i++) {
+      snprintf (vbds[i].node_name, sizeof (vbds[i].node_name),
+               "device/vbd/%s", dirs[i]);
+      vbds[i].handle = simple_strtoul(dirs[i], NULL, 0);
+    }
+    for (i = 0; i < nbr_entries; i++) {
+      if (find_backend (&vbds[i]) != 0) {
+       printk ("vbd: failed to find backend for %s\n", vbds[i].node_name);
+       continue;
+      }
+      if (setup_blkring (&vbds[i]) != 0) {
+       printk ("vbd: failed to setup %s\n", vbds[i].node_name);
+       continue;
+      }
+      if (talk_to_backend (&vbds[i]) != 0) {
+       printk ("vbd: failed to talk to backend %s\n", vbds[i].node_name);
+       continue;
+      }
+      if (wait_backend (&vbds[i]) != 0) {
+       printk ("vbd: backend is not ready %s\n", vbds[i].node_name);
+       continue;
+      }
+      if (vbd_connect (&vbds[i]) != 0) {
+       printk ("vbd: cannot get backend info: %s\n", vbds[i].node_name);
+       continue;
+      }
+      vbds[i].state = 1;
+
+      char buf[64];
+      snprintf(buf, sizeof(buf), "hd%c", i + 'a');
+      bs_table[i] = bdrv_new(buf);
+      if (bdrv_open_vbd(bs_table[i], &vbds[i], 0) < 0) {
+       printk("qemu: could not open hard disk image '%s'\n", buf);
+       exit();
+      }
+    }
+}
+
+int
+vbd_request(struct vbd_info *info,
+           int op_write, unsigned long sector, char *buf)
+{
+       blkif_request_t *ring_req;
+       static unsigned long id = 0x12;
+       grant_ref_t ref;
+       unsigned long buf_off;
+
+       //printf ("vbd_request: sec=%d buf=%p\n", sector, buf);
+       
+#if 0
+       if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
+               return -1;
+#endif
+
+       ref = gnttab_grant_access (info->otherend_id, addr_to_mfn (buf),
+                                  op_write);
+
+       /* Fill out a communications ring structure. */
+       ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
+
+       ring_req->id = ++id;
+       ring_req->sector_number = (blkif_sector_t)sector;
+       ring_req->handle = info->handle;
+
+       ring_req->operation = op_write ? BLKIF_OP_WRITE : BLKIF_OP_READ;
+
+       ring_req->nr_segments = 0;
+       buf_off = ((unsigned long)buf & (PAGE_SIZE - 1)) >> 9;
+       ring_req->seg[ring_req->nr_segments] =
+         (struct blkif_request_segment) {
+           .gref       = ref,
+           .first_sect = buf_off,
+           .last_sect  = buf_off};
+
+       ring_req->nr_segments++;
+       info->ring.req_prod_pvt++;
+
+       int notify;
+
+       RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify);
+
+       notify_remote_via_evtchn(info->evtchn);
+
+       /* Keep a private copy so we can reissue requests when recovering. */
+       //info->shadow[id].req = *ring_req;
+
+       //gnttab_free_grant_references(gref_head);
+
+       /* Wait for reply.  */
+       RING_IDX i, rp;
+       do {
+         poll_evtchn (info->evtchn);
+
+         rp = info->ring.sring->rsp_prod;
+         rmb(); /* Ensure we see queued responses up to 'rp'. */
+         //printk ("vbd wait: %u %u\n", rp, info->ring.rsp_cons);
+       } while (rp == info->ring.rsp_cons);
+
+
+       rp = info->ring.sring->rsp_prod;
+       rmb(); /* Ensure we see queued responses up to 'rp'. */
+
+       for (i = info->ring.rsp_cons; i != rp; i++) {
+               blkif_response_t *bret;
+
+               bret = RING_GET_RESPONSE(&info->ring, i);
+               if (bret->id != id) {
+                 printk ("Bad id (%lx expect %lx)\n", bret->id, id);
+                 exit();
+               }
+               //printk ("ret: op=%u status=%u, id=%lu\n",
+               //bret->operation, bret->status, bret->id);
+               //req  = (struct request *)info->shadow[id].request;
+
+               //blkif_completion(&info->shadow[id]);
+
+               //ADD_ID_TO_FREELIST(info, id);
+
+               //uptodate = (bret->status == BLKIF_RSP_OKAY);
+               switch (bret->operation) {
+               case BLKIF_OP_READ:
+               case BLKIF_OP_WRITE:
+                       if (unlikely(bret->status != BLKIF_RSP_OKAY))
+                         printk("Bad return from blkdev data "
+                                "request: %x\n", bret->status);
+                       break;
+               default:
+                       BUG();
+               }
+       }
+
+       gnttab_end_access (ref);
+
+       info->ring.rsp_cons = i;
+
+       if (i != info->ring.req_prod_pvt) {
+               int more_to_do;
+               RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do);
+#if 0
+               if (more_to_do)
+                       goto again;
+#endif
+       } else
+               info->ring.sring->rsp_event = i + 1;
+
+       return 0;
+}
+
+void
+vbd_test (void)
+{
+  int i;
+  char *buf = (char *)PAGE_SIZE; // alloc_free_page ();
+  int j;
+  int sect;
+
+  for (i = 0; i < MAX_VBD; i++) {
+    if (vbds[i].state != 1)
+      continue;
+    for (sect = 2; sect < 4; sect++) {
+      printk ("Sector %d of %s:\n", sect, vbds[i].node_name);
+
+      for (j = 0; j < 64; j++)
+       buf[j] = j ^ 0x51;
+
+      vbd_request (&vbds[i], 0, sect, buf);
+
+      for (j = 0; j < 64; j += 16) {
+       int k;
+       printk ("%04x:", j);
+       for (k = 0; k < 16; k++)
+         printk (" %02x", (unsigned char)buf[j + k]);
+       printk ("\n");
+      }
+    }
+  }
+}
+
diff -r 092232fa1fbd extras/stubfw/vbd.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/vbd.h       Sat Nov 17 02:58:51 2007 +0100
@@ -0,0 +1,25 @@
+#ifndef __VBD_H__
+#define __VBD_H__
+#include <xen/xen.h>
+#include <xen/event_channel.h>
+#include <xen/io/blkif.h>
+
+struct vbd_info {
+  unsigned int state;
+  char node_name[24];
+  char backend[256];
+  unsigned int handle;
+  int ring_ref;
+  domid_t otherend_id;
+  blkif_front_ring_t ring;
+  evtchn_port_t evtchn;
+  unsigned long sectors;
+  unsigned long sector_size;
+  unsigned char is_ro;
+};
+
+int
+vbd_request(struct vbd_info *info,
+           int op_write, unsigned long sector, char *buf);
+
+#endif
diff -r 092232fa1fbd extras/stubfw/xenbus.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/xenbus.c    Wed Nov 14 03:42:54 2007 +0100
@@ -0,0 +1,518 @@
+/* 
+ ****************************************************************************
+ * (C) 2006 - Cambridge University
+ ****************************************************************************
+ *
+ *        File: xenbus.c
+ *      Author: Steven Smith (sos22@xxxxxxxxx) 
+ *     Changes: Grzegorz Milos (gm281@xxxxxxxxx)
+ *     Changes: John D. Ramsdell
+ *              
+ *        Date: Jun 2006, chages Aug 2005
+ * 
+ * Environment: Xen Minimal OS
+ * Description: Minimal implementation of xenbus
+ *
+ ****************************************************************************
+ **/
+#include "os.h"
+#include "lib.h"
+#include "xenbus.h"
+#include "events.h"
+#include <xen/io/xs_wire.h>
+
+//#define XENBUS_DEBUG
+
+#define BUG_ON(x) do { \
+    if (x) {printk("BUG at %s:%d\n", __FILE__, __LINE__); BUG(); } \
+} while (0)
+
+#define min(x,y) ({                       \
+        typeof(x) tmpx = (x);                 \
+        typeof(y) tmpy = (y);                 \
+        tmpx < tmpy ? tmpx : tmpy;            \
+        })
+
+#ifdef XENBUS_DEBUG
+#define DEBUG(_f, _a...) \
+    printk("MINI_OS(file=xenbus.c, line=%d) " _f , __LINE__, ## _a)
+#else
+#define DEBUG(_f, _a...)    ((void)0)
+#endif
+
+static volatile struct xenstore_domain_interface *xenstore_buf;
+static int xenstore_evtchn;
+
+struct xenbus_req
+{
+    int id;
+
+    struct xsd_sockmsg reply;
+    char *reply_buf;
+    size_t reply_size;
+};
+
+#define NR_REQS 32
+static struct xenbus_req xb_reqs[NR_REQS];
+static int next_xb_reqs;
+
+struct xenbus_req *
+xenbus_allocate_req (char *buf, int size)
+{
+    if (next_xb_reqs == NR_REQS)
+       return NULL;
+    xb_reqs[next_xb_reqs].reply_buf = buf;
+    xb_reqs[next_xb_reqs].reply_size = size;
+    return &xb_reqs[next_xb_reqs++];
+}
+
+static void memcpy_from_ring(const void *Ring,
+        void *Dest,
+        int off,
+        int len)
+{
+    int c1, c2;
+    const char *ring = Ring;
+    char *dest = Dest;
+    c1 = min(len, XENSTORE_RING_SIZE - off);
+    c2 = len - c1;
+    memcpy(dest, ring + off, c1);
+    memcpy(dest + c1, ring, c2);
+}
+
+static void
+xenbus_wait_event (void)
+{
+    int res;
+    evtchn_port_t port = xenstore_evtchn;
+    sched_poll_t poll;
+
+    set_xen_guest_handle (poll.ports, &port);
+    poll.nr_ports = 1;
+    poll.timeout = 1000000000UL;
+    res = HYPERVISOR_poll (&poll);
+    //printk ("poll: res=%d\n", res);
+}
+
+static void 
+xenbus_wait_reply (struct xenbus_req *req)
+{
+    struct xsd_sockmsg msg;
+    unsigned prod;
+
+    while (1) {
+       prod = xenstore_buf->rsp_prod;
+       DEBUG("Rsp_cons %d, rsp_prod %d.\n", xenstore_buf->rsp_cons,
+             xenstore_buf->rsp_prod);
+       while (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons < sizeof(msg))
+           xenbus_wait_event ();
+       rmb();
+       memcpy_from_ring((char *)xenstore_buf->rsp,
+                        &msg,
+                        MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
+                        sizeof(msg));
+       DEBUG("Msg len %d+%d, %d avail, id %d.\n",
+             sizeof(msg), msg.len,
+             xenstore_buf->rsp_prod - xenstore_buf->rsp_cons,
+             msg.req_id);
+       while (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons <
+              sizeof(msg) + msg.len)
+           xenbus_wait_event ();
+       
+       DEBUG("Message is good type=%d.\n", msg.type);
+       
+       if (msg.type == XS_WATCH_EVENT) {
+           printk ("Unexpected watch event\n");
+           xenstore_buf->rsp_cons += msg.len + sizeof(msg);
+#if 0
+           char* payload = (char*)malloc(sizeof(msg) + msg.len);
+           char *path,*token;
+           
+           memcpy_from_ring(xenstore_buf->rsp,
+                            payload,
+                            MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
+                            msg.len + sizeof(msg));
+           
+           path = payload + sizeof(msg);
+           token = path + strlen(path) + 1;
+           
+           xenstore_buf->rsp_cons += msg.len + sizeof(msg);
+           free(payload);
+           wake_up(&watch_queue);
+#endif
+       }
+       else {
+           size_t len;
+           if (msg.req_id != req->id) {
+               printk ("unexpected reply for %d (was waiting for %d)\n",
+                       msg.req_id, req->id);
+           }
+           else {
+               memcpy (&req->reply, &msg, sizeof (msg));
+               xenstore_buf->rsp_cons += sizeof(msg);
+               len = min (msg.len, req->reply_size - 1);
+               memcpy_from_ring((char *)xenstore_buf->rsp,
+                                req->reply_buf,
+                                MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
+                                len);
+               /* Always put a NUL.  */
+               req->reply_buf[len] = 0;
+               xenstore_buf->rsp_cons += msg.len;
+               return;
+           }
+       }
+    }
+}
+
+static void xenbus_evtchn_handler(evtchn_port_t port, void *ign)
+{
+    printk ("xenbus event!\n");
+    //    wake_up(&xb_waitq);
+}
+
+/* Initialise xenbus. */
+void init_xenbus(void *interface, int evtchn)
+{
+    int err;
+    int i;
+
+    printk("Initialising xenbus\n");
+    DEBUG("init_xenbus called.\n");
+    xenstore_buf = (struct xenstore_domain_interface *)interface;
+    //create_thread("xenstore", xenbus_thread_func, NULL);
+    DEBUG("buf at %p.\n", xenstore_buf);
+    xenstore_evtchn = evtchn;
+    err = bind_evtchn(evtchn, xenbus_evtchn_handler, NULL);
+    DEBUG("xenbus on irq %d\n", err);
+
+    for (i = 0; i < NR_REQS; i++) {
+       xb_reqs[i].id = (i << 8) + 1;
+       xb_reqs[i].reply_size = 0;
+    }
+}
+
+const char*
+xenbus_wait_for_value(struct xenbus_req *r,
+                     const char* path, const char* value)
+{
+    while (1) {
+       const char *msg;
+        char *res;
+
+        msg = xenbus_read(r, XBT_NIL, path, &res);
+        if (msg)
+           return msg;
+       DEBUG("xenbus_wait_for_value: get %s, expect %s\n", res, value);
+        if (strcmp (value, res) == 0)
+           return NULL;
+       xenbus_wait_event ();
+    }
+}
+
+struct write_req {
+    const void *data;
+    unsigned len;
+};
+
+/* Send data to xenbus.  This can block.  All of the requests are seen
+   by xenbus as if sent atomically.  The header is added
+   automatically, using type %type, req_id %req_id, and trans_id
+   %trans_id. */
+static void xb_write(int type, struct xenbus_req *xb_req,
+                    xenbus_transaction_t trans_id,
+                    const struct write_req *req, int nr_reqs)
+{
+    XENSTORE_RING_IDX prod;
+    int r;
+    int len = 0;
+    const struct write_req *cur_req;
+    int req_off;
+    int total_off;
+    int this_chunk;
+    struct xsd_sockmsg m = {.type = type,
+                           .req_id = xb_req->id,
+                           .tx_id = trans_id };
+    struct write_req header_req = { &m, sizeof(m) };
+
+    for (r = 0; r < nr_reqs; r++)
+        len += req[r].len;
+    m.len = len;
+    len += sizeof(m);
+
+    cur_req = &header_req;
+
+    BUG_ON(len > XENSTORE_RING_SIZE);
+    /* Wait for the ring to drain to the point where we can send the
+       message. */
+    prod = xenstore_buf->req_prod;
+    if (prod + len - xenstore_buf->req_cons > XENSTORE_RING_SIZE) 
+    {
+       BUG();
+#if 0
+        /* Wait for there to be space on the ring */
+        DEBUG("prod %d, len %d, cons %d, size %d; waiting.\n",
+                prod, len, xenstore_buf->req_cons, XENSTORE_RING_SIZE);
+        wait_event(xb_waitq,
+                xenstore_buf->req_prod + len - xenstore_buf->req_cons <=
+                XENSTORE_RING_SIZE);
+        DEBUG("Back from wait.\n");
+        prod = xenstore_buf->req_prod;
+#endif
+    }
+
+    /* We're now guaranteed to be able to send the message without
+       overflowing the ring.  Do so. */
+    total_off = 0;
+    req_off = 0;
+    while (total_off < len) 
+    {
+        this_chunk = min(cur_req->len - req_off,
+                XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
+        memcpy((char *)xenstore_buf->req + MASK_XENSTORE_IDX(prod),
+                (char *)cur_req->data + req_off, this_chunk);
+        prod += this_chunk;
+        req_off += this_chunk;
+        total_off += this_chunk;
+        if (req_off == cur_req->len) 
+        {
+            req_off = 0;
+            if (cur_req == &header_req)
+                cur_req = req;
+            else
+                cur_req++;
+        }
+    }
+
+    DEBUG("Complete main loop of xb_write.\n");
+    BUG_ON(req_off != 0);
+    BUG_ON(total_off != len);
+    BUG_ON(prod > xenstore_buf->req_cons + XENSTORE_RING_SIZE);
+
+    /* Remote must see entire message before updating indexes */
+    wmb();
+
+    xenstore_buf->req_prod += len;
+
+    /* Send evtchn to notify remote */
+    notify_remote_via_evtchn(xenstore_evtchn);
+}
+
+/* Send a mesasge to xenbus, in the same fashion as xb_write, and
+   block waiting for a reply.  The reply is malloced and should be
+   freed by the caller. */
+static void
+xenbus_msg_reply(int type,
+                struct xenbus_req *req,
+                xenbus_transaction_t trans,
+                struct write_req *io,
+                int nr_reqs)
+{
+    xb_write(type, req, trans, io, nr_reqs);
+
+    xenbus_wait_reply (req);
+}
+
+static const char *errmsg(struct xenbus_req *req)
+{
+    if (!req->reply.len) {
+       return "No reply";
+    }
+    if (req->reply.len > req->reply_size) {
+       return "Truncated reply";
+    }
+    if (req->reply.type != XS_ERROR)
+       return NULL;
+    return req->reply_buf;
+}      
+
+/* Send a debug message to xenbus.  Can block. */
+void xenbus_debug_msg(struct xenbus_req *r, const char *msg)
+{
+    int len = strlen(msg);
+    struct write_req req[] = {
+        { "print", sizeof("print") },
+        { msg, len },
+        { "", 1 }};
+
+    xenbus_msg_reply(XS_DEBUG, r, 0, req, ARRAY_SIZE(req));
+    DEBUG("Got a reply, type %d, id %d, len %d.\n",
+            r->reply.type, r->reply.req_id, r->reply.len);
+}
+
+/* List the contents of a directory.  Returns a malloc()ed array of
+   pointers to malloc()ed strings.  The array is NULL terminated.  May
+   block. */
+const char *xenbus_ls(struct xenbus_req *r, xenbus_transaction_t xbt,
+                     const char *dir, char **contents, int *contents_len)
+{
+    char *reply;
+    struct write_req req[] = { { dir, strlen(dir)+1 } };
+    int nr_elems, x;
+
+    xenbus_msg_reply(XS_DIRECTORY, r, xbt, req, ARRAY_SIZE(req));
+    const char *msg = errmsg(r);
+    if (msg) {
+       *contents = NULL;
+       return msg;
+    }
+    /* Count number of elements.  */
+    reply = r->reply_buf;
+    if (*contents_len > 0)
+       contents[0] = reply;
+    for (x = nr_elems = 0; x < r->reply.len; x++, reply++) {
+       if (*reply == 0) {
+           nr_elems++;
+           if (nr_elems < *contents_len)
+               contents[nr_elems] = reply + 1;
+       }
+    }
+    *contents_len = nr_elems;
+    return NULL;
+}
+
+const char *
+xenbus_read(struct xenbus_req *r, xenbus_transaction_t xbt,
+           const char *path, char **value)
+{
+    struct write_req req[] = { {path, strlen(path) + 1} };
+    xenbus_msg_reply(XS_READ, r, xbt, req, ARRAY_SIZE(req));
+    const char *msg = errmsg(r);
+    if (msg) {
+       *value = NULL;
+       return msg;
+    }
+    *value = r->reply_buf;
+    return NULL;
+}
+
+const char *xenbus_write(struct xenbus_req *r, xenbus_transaction_t xbt, const 
char *path, const char *value)
+{
+    struct write_req req[] = { 
+       {path, strlen(path) + 1},
+       {value, strlen(value) + 1},
+    };
+    xenbus_msg_reply(XS_WRITE, r, xbt, req, ARRAY_SIZE(req));
+    const char *msg = errmsg(r);
+    if (msg)
+       return msg;
+    return NULL;
+}
+
+const char*
+xenbus_watch_path(struct xenbus_req *r, xenbus_transaction_t xbt,
+                 const char *path)
+{
+    /* in the future one could have multiple watch queues, and use
+     * the token for demuxing. For now the token is 0. */
+    struct write_req req[] = { 
+        {path, strlen(path) + 1},
+        {"0",2 },
+    };
+
+    xenbus_msg_reply(XS_WATCH, r, xbt, req, ARRAY_SIZE(req));
+
+    const char *msg = errmsg(r);
+    if (msg)
+       return msg;
+    return NULL;
+}
+
+const char *xenbus_rm(struct xenbus_req *r, xenbus_transaction_t xbt, const 
char *path)
+{
+    struct write_req req[] = { {path, strlen(path) + 1} };
+    xenbus_msg_reply(XS_RM, r, xbt, req, ARRAY_SIZE(req));
+    const char *msg = errmsg(r);
+    if (msg)
+       return msg;
+    return NULL;
+}
+
+const char *xenbus_get_perms(struct xenbus_req *r, xenbus_transaction_t xbt, 
const char *path, char **value)
+{
+    struct write_req req[] = { {path, strlen(path) + 1} };
+    xenbus_msg_reply(XS_GET_PERMS, r, xbt, req, ARRAY_SIZE(req));
+    const char *msg = errmsg(r);
+    if (msg) {
+       *value = NULL;
+       return msg;
+    }
+    *value = r->reply_buf;
+    return NULL;
+}
+
+#define PERM_MAX_SIZE 32
+const char *xenbus_set_perms(struct xenbus_req *r, xenbus_transaction_t xbt, 
const char *path, domid_t dom, char perm)
+{
+    char value[PERM_MAX_SIZE];
+    snprintf(value, PERM_MAX_SIZE, "%c%hu", perm, dom);
+    struct write_req req[] = { 
+       {path, strlen(path) + 1},
+       {value, strlen(value) + 1},
+    };
+    xenbus_msg_reply(XS_SET_PERMS, r, xbt, req, ARRAY_SIZE(req));
+    const char *msg = errmsg(r);
+    if (msg)
+       return msg;
+    return NULL;
+}
+
+const char *xenbus_transaction_start(struct xenbus_req *r, 
xenbus_transaction_t *xbt)
+{
+    /* xenstored becomes angry if you send a length 0 message, so just
+       shove a nul terminator on the end */
+    struct write_req req = { "", 1};
+    const char *err;
+
+    xenbus_msg_reply(XS_TRANSACTION_START, r, 0, &req, 1);
+    err = errmsg(r);
+    if (err)
+       return err;
+    sscanf(r->reply_buf, "%u", xbt);
+    return NULL;
+}
+
+const char *
+xenbus_transaction_end(struct xenbus_req *r, xenbus_transaction_t t, int 
abort, int *retry)
+{
+    struct write_req req;
+    const char *err;
+
+    *retry = 0;
+
+    req.data = abort ? "F" : "T";
+    req.len = 2;
+    xenbus_msg_reply(XS_TRANSACTION_END, r, t, &req, 1);
+    err = errmsg(r);
+    if (err) {
+       if (!strcmp(err, "EAGAIN")) {
+           *retry = 1;
+           return NULL;
+       } else {
+           return err;
+       }
+    }
+    return NULL;
+}
+
+int xenbus_read_integer(struct xenbus_req *r, char *path)
+{
+    const char *res;
+    char *buf;
+    int t;
+
+    res = xenbus_read(r, XBT_NIL, path, &buf);
+    if (res) {
+       printk("Failed to read %s.\n", path);
+       return -1;
+    }
+    sscanf(buf, "%d", &t);
+    return t;
+}
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * End:
+ */
diff -r 092232fa1fbd extras/stubfw/xenbus_test.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/stubfw/xenbus_test.c       Wed Nov 14 01:47:42 2007 +0100
@@ -0,0 +1,90 @@
+#include "os.h"
+#include "lib.h"
+#include "xenbus.h"
+#include "events.h"
+#include <xen/io/xs_wire.h>
+
+static void do_ls_test(struct xenbus_req *r, const char *pre)
+{
+#define MAX_ENTRIES 32
+    char *dirs[MAX_ENTRIES];
+    int len = MAX_ENTRIES;
+    int x;
+
+    printk("ls %s...\n", pre);
+    const char *msg = xenbus_ls(r, XBT_NIL, pre, dirs, &len);
+    if (msg) {
+       printk("Error in xenbus ls: %s\n", msg);
+       return;
+    }
+    if (len > MAX_ENTRIES)
+       len = MAX_ENTRIES;
+    for (x = 0; x < len; x++) 
+    {
+        printk("ls %s[%d] -> %s\n", pre, x, dirs[x]);
+    }
+}
+
+static void do_read_test(struct xenbus_req *r, const char *path)
+{
+    char *res;
+    printk("Read %s...\n", path);
+    const char *msg = xenbus_read(r, XBT_NIL, path, &res);
+    if (msg) {
+       printk("Error in xenbus read: %s\n", msg);
+       return;
+    }
+    printk("Read %s -> %s.\n", path, res);
+}
+
+static void do_write_test(struct xenbus_req *r, const char *path, const char 
*val)
+{
+    printk("Write %s to %s...\n", val, path);
+    const char *msg = xenbus_write(r, XBT_NIL, path, val);
+    if (msg) {
+       printk("Result %s\n", msg);
+    } else {
+       printk("Success.\n");
+    }
+}
+
+static void do_rm_test(struct xenbus_req *r, const char *path)
+{
+    printk("rm %s...\n", path);
+    const char *msg = xenbus_rm(r, XBT_NIL, path);
+    if (msg) {
+       printk("Result %s\n", msg);
+    } else {
+       printk("Success.\n");
+    }
+}
+
+/* Simple testing thing */
+void test_xenbus(void)
+{
+    char buf[1024];
+    struct xenbus_req *r = xenbus_allocate_req (buf, sizeof (buf));
+
+    printk("Doing xenbus test.\n");
+    xenbus_debug_msg(r, "Testing xenbus...\n");
+
+    printk("Doing ls test.\n");
+    do_ls_test(r, "device");
+    do_ls_test(r, "device/vbd");
+    do_ls_test(r, "device/vbd/769");
+
+    printk("Doing read test.\n");
+    do_read_test(r, "device/vif/0/mac");
+    do_read_test(r, "device/vif/0/backend");
+
+    printk("Doing write test.\n");
+    do_write_test(r, "device/vif/0/flibble", "flobble");
+    do_read_test(r, "device/vif/0/flibble");
+    do_write_test(r, "device/vif/0/flibble", "widget");
+    do_read_test(r, "device/vif/0/flibble");
+
+    printk("Doing rm test.\n");
+    do_rm_test(r, "device/vif/0/flibble");
+    do_read_test(r, "device/vif/0/flibble");
+    printk("(Should have said ENOENT)\n");
+}

_______________________________________________
Xen-ia64-devel mailing list
Xen-ia64-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-ia64-devel

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-ia64-devel] [RFC 3/3] hvm-stub for ia64: stubfw, tgingold <=