[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-ia64-devel] [RFC 3/3] hvm-stub for ia64: stubfw
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(®, 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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |